├── .babelrc ├── .editorconfig ├── .eslintrc ├── .github ├── FUNDING.yml └── workflows │ └── CI.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .npmrc ├── .nvmrc ├── BACKERS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.ar-AR.md ├── README.de-DE.md ├── README.es-ES.md ├── README.fr-FR.md ├── README.he-IL.md ├── README.id-ID.md ├── README.it-IT.md ├── README.ja-JP.md ├── README.ko-KR.md ├── README.md ├── README.pl-PL.md ├── README.pt-BR.md ├── README.ru-RU.md ├── README.tr-TR.md ├── README.uk-UA.md ├── README.uz-UZ.md ├── README.vi-VN.md ├── README.zh-CN.md ├── README.zh-TW.md ├── assets └── big-o-graph.png ├── jest.config.js ├── package-lock.json ├── package.json └── src ├── algorithms ├── cryptography │ ├── caesar-cipher │ │ ├── README.md │ │ ├── README.ru-RU.md │ │ ├── __test__ │ │ │ └── caesarCipher.test.js │ │ └── caesarCipher.js │ ├── hill-cipher │ │ ├── README.md │ │ ├── _test_ │ │ │ └── hillCipher.test.js │ │ └── hillCipher.js │ ├── polynomial-hash │ │ ├── PolynomialHash.js │ │ ├── README.md │ │ ├── SimplePolynomialHash.js │ │ └── __test__ │ │ │ ├── PolynomialHash.test.js │ │ │ └── SimplePolynomialHash.test.js │ └── rail-fence-cipher │ │ ├── README.md │ │ ├── __test__ │ │ └── railFenceCipher.test.js │ │ └── railFenceCipher.js ├── graph │ ├── articulation-points │ │ ├── README.md │ │ ├── __test__ │ │ │ └── articulationPoints.test.js │ │ └── articulationPoints.js │ ├── bellman-ford │ │ ├── README.md │ │ ├── __test__ │ │ │ └── bellmanFord.test.js │ │ └── bellmanFord.js │ ├── breadth-first-search │ │ ├── README.md │ │ ├── __test__ │ │ │ └── breadthFirstSearch.test.js │ │ └── breadthFirstSearch.js │ ├── bridges │ │ ├── README.md │ │ ├── __test__ │ │ │ └── graphBridges.test.js │ │ └── graphBridges.js │ ├── depth-first-search │ │ ├── README.md │ │ ├── __test__ │ │ │ └── depthFirstSearch.test.js │ │ └── depthFirstSearch.js │ ├── detect-cycle │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── detectDirectedCycle.test.js │ │ │ ├── detectUndirectedCycle.test.js │ │ │ └── detectUndirectedCycleUsingDisjointSet.test.js │ │ ├── detectDirectedCycle.js │ │ ├── detectUndirectedCycle.js │ │ └── detectUndirectedCycleUsingDisjointSet.js │ ├── dijkstra │ │ ├── README.ko-KR.md │ │ ├── README.md │ │ ├── __test__ │ │ │ └── dijkstra.test.js │ │ └── dijkstra.js │ ├── eulerian-path │ │ ├── README.md │ │ ├── __test__ │ │ │ └── eulerianPath.test.js │ │ └── eulerianPath.js │ ├── floyd-warshall │ │ ├── README.md │ │ ├── __test__ │ │ │ └── floydWarshall.test.js │ │ └── floydWarshall.js │ ├── hamiltonian-cycle │ │ ├── README.md │ │ ├── __test__ │ │ │ └── hamiltonianCycle.test.js │ │ └── hamiltonianCycle.js │ ├── kruskal │ │ ├── README.ko-KR.md │ │ ├── README.md │ │ ├── __test__ │ │ │ └── kruskal.test.js │ │ └── kruskal.js │ ├── prim │ │ ├── README.md │ │ ├── __test__ │ │ │ └── prim.test.js │ │ └── prim.js │ ├── strongly-connected-components │ │ ├── README.md │ │ ├── __test__ │ │ │ └── stronglyConnectedComponents.test.js │ │ └── stronglyConnectedComponents.js │ ├── topological-sorting │ │ ├── README.md │ │ ├── __test__ │ │ │ └── topologicalSort.test.js │ │ └── topologicalSort.js │ └── travelling-salesman │ │ ├── README.md │ │ ├── __test__ │ │ └── bfTravellingSalesman.test.js │ │ └── bfTravellingSalesman.js ├── image-processing │ ├── seam-carving │ │ ├── README.md │ │ ├── README.ru-RU.md │ │ ├── __tests__ │ │ │ ├── resizeImageWidth.node.js │ │ │ ├── test-image-after.png │ │ │ └── test-image-before.png │ │ └── resizeImageWidth.js │ └── utils │ │ └── imageData.js ├── linked-list │ ├── reverse-traversal │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ │ └── reverseTraversal.test.js │ │ └── reverseTraversal.js │ └── traversal │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── README.ru-RU.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ └── traversal.test.js │ │ └── traversal.js ├── math │ ├── binary-floating-point │ │ ├── README.md │ │ ├── __tests__ │ │ │ ├── bitsToFloat.test.js │ │ │ └── floatAsBinaryString.test.js │ │ ├── bitsToFloat.js │ │ ├── floatAsBinaryString.js │ │ ├── images │ │ │ ├── 02-half-precision-floating-point-number-explained.png │ │ │ └── 03-scientific-notation.png │ │ └── testCases.js │ ├── bits │ │ ├── README.fr-FR.md │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ │ ├── bitLength.test.js │ │ │ ├── bitsDiff.test.js │ │ │ ├── clearBit.test.js │ │ │ ├── countSetBits.test.js │ │ │ ├── divideByTwo.test.js │ │ │ ├── fullAdder.test.js │ │ │ ├── getBit.test.js │ │ │ ├── isEven.test.js │ │ │ ├── isPositive.test.js │ │ │ ├── isPowerOfTwo.test.js │ │ │ ├── multiply.test.js │ │ │ ├── multiplyByTwo.test.js │ │ │ ├── multiplyUnsigned.test.js │ │ │ ├── setBit.test.js │ │ │ ├── switchSign.test.js │ │ │ └── updateBit.test.js │ │ ├── bitLength.js │ │ ├── bitsDiff.js │ │ ├── clearBit.js │ │ ├── countSetBits.js │ │ ├── divideByTwo.js │ │ ├── fullAdder.js │ │ ├── getBit.js │ │ ├── isEven.js │ │ ├── isPositive.js │ │ ├── isPowerOfTwo.js │ │ ├── multiply.js │ │ ├── multiplyByTwo.js │ │ ├── multiplyUnsigned.js │ │ ├── setBit.js │ │ ├── switchSign.js │ │ └── updateBit.js │ ├── complex-number │ │ ├── ComplexNumber.js │ │ ├── README.fr-FR.md │ │ ├── README.md │ │ └── __test__ │ │ │ └── ComplexNumber.test.js │ ├── euclidean-algorithm │ │ ├── README.fr-FR.md │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── euclideanAlgorithm.test.js │ │ │ └── euclideanAlgorithmIterative.test.js │ │ ├── euclideanAlgorithm.js │ │ └── euclideanAlgorithmIterative.js │ ├── euclidean-distance │ │ ├── README.md │ │ ├── __tests__ │ │ │ └── euclideanDistance.test.js │ │ └── euclideanDistance.js │ ├── factorial │ │ ├── README.fr-FR.md │ │ ├── README.ka-GE.md │ │ ├── README.md │ │ ├── README.tr-TR.md │ │ ├── README.uk-UA.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ │ ├── factorial.test.js │ │ │ └── factorialRecursive.test.js │ │ ├── factorial.js │ │ └── factorialRecursive.js │ ├── fast-powering │ │ ├── README.fr-FR.md │ │ ├── README.md │ │ ├── __test__ │ │ │ └── fastPowering.test.js │ │ └── fastPowering.js │ ├── fibonacci │ │ ├── README.fr-FR.md │ │ ├── README.ka-GE.md │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ │ ├── fibonacci.test.js │ │ │ ├── fibonacciNth.test.js │ │ │ └── fibonacciNthClosedForm.test.js │ │ ├── fibonacci.js │ │ ├── fibonacciNth.js │ │ └── fibonacciNthClosedForm.js │ ├── fourier-transform │ │ ├── README.fr-FR.md │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── FourierTester.js │ │ │ ├── discreteFourierTransform.test.js │ │ │ ├── fastFourierTransform.test.js │ │ │ └── inverseDiscreteFourierTransform.test.js │ │ ├── discreteFourierTransform.js │ │ ├── fastFourierTransform.js │ │ └── inverseDiscreteFourierTransform.js │ ├── horner-method │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── classicPolynome.test.js │ │ │ └── hornerMethod.test.js │ │ ├── classicPolynome.js │ │ └── hornerMethod.js │ ├── integer-partition │ │ ├── README.md │ │ ├── __test__ │ │ │ └── integerPartition.test.js │ │ └── integerPartition.js │ ├── is-power-of-two │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── isPowerOfTwo.test.js │ │ │ └── isPowerOfTwoBitwise.test.js │ │ ├── isPowerOfTwo.js │ │ └── isPowerOfTwoBitwise.js │ ├── least-common-multiple │ │ ├── README.md │ │ ├── __test__ │ │ │ └── leastCommonMultiple.test.js │ │ └── leastCommonMultiple.js │ ├── liu-hui │ │ ├── README.md │ │ ├── __test__ │ │ │ └── liuHui.test.js │ │ └── liuHui.js │ ├── matrix │ │ ├── Matrix.js │ │ ├── README.md │ │ └── __tests__ │ │ │ └── Matrix.test.js │ ├── pascal-triangle │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── pascalTriangle.test.js │ │ │ └── pascalTriangleRecursive.test.js │ │ ├── pascalTriangle.js │ │ └── pascalTriangleRecursive.js │ ├── primality-test │ │ ├── README.md │ │ ├── __test__ │ │ │ └── trialDivision.test.js │ │ └── trialDivision.js │ ├── prime-factors │ │ ├── README.md │ │ ├── README.zh-CN.md │ │ ├── __test__ │ │ │ └── primeFactors.test.js │ │ └── primeFactors.js │ ├── radian │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── degreeToRadian.test.js │ │ │ └── radianToDegree.test.js │ │ ├── degreeToRadian.js │ │ └── radianToDegree.js │ ├── sieve-of-eratosthenes │ │ ├── README.md │ │ ├── __test__ │ │ │ └── sieveOfEratosthenes.test.js │ │ └── sieveOfEratosthenes.js │ └── square-root │ │ ├── README.md │ │ ├── __test__ │ │ └── squareRoot.test.js │ │ └── squareRoot.js ├── ml │ ├── k-means │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── __test__ │ │ │ └── kMeans.test.js │ │ └── kMeans.js │ └── knn │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── __test__ │ │ └── knn.test.js │ │ └── kNN.js ├── search │ ├── binary-search │ │ ├── README.es-ES.md │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── __test__ │ │ │ └── binarySearch.test.js │ │ └── binarySearch.js │ ├── interpolation-search │ │ ├── README.md │ │ ├── __test__ │ │ │ └── interpolationSearch.test.js │ │ └── interpolationSearch.js │ ├── jump-search │ │ ├── README.md │ │ ├── __test__ │ │ │ └── jumpSearch.test.js │ │ └── jumpSearch.js │ └── linear-search │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── __test__ │ │ └── linearSearch.test.js │ │ └── linearSearch.js ├── sets │ ├── cartesian-product │ │ ├── README.md │ │ ├── __test__ │ │ │ └── cartesianProduct.test.js │ │ └── cartesianProduct.js │ ├── combination-sum │ │ ├── README.md │ │ ├── __test__ │ │ │ └── combinationSum.test.js │ │ └── combinationSum.js │ ├── combinations │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── combineWithRepetitions.test.js │ │ │ └── combineWithoutRepetitions.test.js │ │ ├── combineWithRepetitions.js │ │ ├── combineWithoutRepetitions.js │ │ └── images │ │ │ ├── combinations-overview.jpg │ │ │ ├── combinations-with-repetitions.jpg │ │ │ ├── combinations-without-repetitions.jpg │ │ │ └── overview.png │ ├── fisher-yates │ │ ├── README.md │ │ ├── __test__ │ │ │ └── fisherYates.test.js │ │ └── fisherYates.js │ ├── knapsack-problem │ │ ├── Knapsack.js │ │ ├── KnapsackItem.js │ │ ├── README.md │ │ └── __test__ │ │ │ ├── Knapsack.test.js │ │ │ └── KnapsackItem.test.js │ ├── longest-common-subsequence │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── longestCommonSubsequence.test.js │ │ │ └── longestCommonSubsequenceRecursive.test.js │ │ ├── longestCommonSubsequence.js │ │ └── longestCommonSubsequenceRecursive.js │ ├── longest-increasing-subsequence │ │ ├── README.md │ │ ├── __test__ │ │ │ └── dpLongestIncreasingSubsequence.test.js │ │ └── dpLongestIncreasingSubsequence.js │ ├── maximum-subarray │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── bfMaximumSubarray.test.js │ │ │ ├── dcMaximumSubarraySum.test.js │ │ │ └── dpMaximumSubarray.test.js │ │ ├── bfMaximumSubarray.js │ │ ├── dcMaximumSubarraySum.js │ │ └── dpMaximumSubarray.js │ ├── permutations │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── permutateWithRepetitions.test.js │ │ │ └── permutateWithoutRepetitions.test.js │ │ ├── images │ │ │ ├── overview.png │ │ │ ├── permutations-overview.jpeg │ │ │ ├── permutations-with-repetitions.jpg │ │ │ └── permutations-without-repetitions.jpg │ │ ├── permutateWithRepetitions.js │ │ └── permutateWithoutRepetitions.js │ ├── power-set │ │ ├── README.md │ │ ├── __test__ │ │ │ ├── btPowerSet.test.js │ │ │ ├── bwPowerSet.test.js │ │ │ └── caPowerSet.test.js │ │ ├── btPowerSet.js │ │ ├── bwPowerSet.js │ │ └── caPowerSet.js │ └── shortest-common-supersequence │ │ ├── README.md │ │ ├── __test__ │ │ └── shortestCommonSupersequence.test.js │ │ └── shortestCommonSupersequence.js ├── sorting │ ├── Sort.js │ ├── SortTester.js │ ├── __test__ │ │ └── Sort.test.js │ ├── bubble-sort │ │ ├── BubbleSort.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── BubbleSort.test.js │ ├── bucket-sort │ │ ├── BucketSort.js │ │ ├── README.md │ │ ├── __test__ │ │ │ └── BucketSort.test.js │ │ └── images │ │ │ ├── bucket_sort_1.png │ │ │ └── bucket_sort_2.png │ ├── counting-sort │ │ ├── CountingSort.js │ │ ├── README.md │ │ ├── README.pt-br.md │ │ └── __test__ │ │ │ └── CountingSort.test.js │ ├── heap-sort │ │ ├── HeapSort.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── HeapSort.test.js │ ├── insertion-sort │ │ ├── InsertionSort.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── InsertionSort.test.js │ ├── merge-sort │ │ ├── MergeSort.js │ │ ├── README.ko-KR.md │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── MergeSort.test.js │ ├── quick-sort │ │ ├── QuickSort.js │ │ ├── QuickSortInPlace.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── README.zh-CN.md │ │ └── __test__ │ │ │ ├── QuickSort.test.js │ │ │ └── QuickSortInPlace.test.js │ ├── radix-sort │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── RadixSort.js │ │ ├── __test__ │ │ │ └── RadixSort.test.js │ │ └── images │ │ │ └── radix-sort.png │ ├── selection-sort │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── SelectionSort.js │ │ └── __test__ │ │ │ └── SelectionSort.test.js │ └── shell-sort │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── ShellSort.js │ │ └── __test__ │ │ └── ShellSort.test.js ├── stack │ └── valid-parentheses │ │ ├── README.md │ │ ├── __test__ │ │ └── validParentheses.test.js │ │ └── validParentheses.js ├── statistics │ └── weighted-random │ │ ├── README.md │ │ ├── __test__ │ │ └── weightedRandom.test.js │ │ ├── images │ │ └── cover.png │ │ └── weightedRandom.js ├── string │ ├── hamming-distance │ │ ├── README.md │ │ ├── __test__ │ │ │ └── hammingDistance.test.js │ │ └── hammingDistance.js │ ├── knuth-morris-pratt │ │ ├── README.md │ │ ├── __test__ │ │ │ └── knuthMorrisPratt.test.js │ │ └── knuthMorrisPratt.js │ ├── levenshtein-distance │ │ ├── README.md │ │ ├── __test__ │ │ │ └── levenshteinDistance.test.js │ │ └── levenshteinDistance.js │ ├── longest-common-substring │ │ ├── README.md │ │ ├── __test__ │ │ │ └── longestCommonSubstring.test.js │ │ └── longestCommonSubstring.js │ ├── palindrome │ │ ├── README.md │ │ ├── __test__ │ │ │ └── isPalindrome.test.js │ │ └── isPalindrome.js │ ├── rabin-karp │ │ ├── README.md │ │ ├── __test__ │ │ │ └── rabinKarp.test.js │ │ └── rabinKarp.js │ ├── regular-expression-matching │ │ ├── README.md │ │ ├── __test__ │ │ │ └── regularExpressionMatching.test.js │ │ └── regularExpressionMatching.js │ └── z-algorithm │ │ ├── README.md │ │ ├── __test__ │ │ └── zAlgorithm.test.js │ │ └── zAlgorithm.js ├── tree │ ├── breadth-first-search │ │ ├── README.md │ │ ├── __test__ │ │ │ └── breadthFirstSearch.test.js │ │ └── breadthFirstSearch.js │ └── depth-first-search │ │ ├── README.md │ │ ├── __test__ │ │ └── depthFirstSearch.test.js │ │ └── depthFirstSearch.js └── uncategorized │ ├── best-time-to-buy-sell-stocks │ ├── README.md │ ├── __tests__ │ │ ├── accumulatorBestTimeToBuySellStocks.test.js │ │ ├── dpBestTimeToBuySellStocks.test.js │ │ ├── dqBestTimeToBuySellStocks.test.js │ │ └── peakvalleyBestTimeToBuySellStocks.test.js │ ├── accumulatorBestTimeToBuySellStocks.js │ ├── dpBestTimeToBuySellStocks.js │ ├── dqBestTimeToBuySellStocks.js │ └── peakvalleyBestTimeToBuySellStocks.js │ ├── hanoi-tower │ ├── README.md │ ├── __test__ │ │ └── hanoiTower.test.js │ └── hanoiTower.js │ ├── jump-game │ ├── README.md │ ├── __test__ │ │ ├── backtrackingJumpGame.test.js │ │ ├── dpBottomUpJumpGame.test.js │ │ ├── dpTopDownJumpGame.test.js │ │ └── greedyJumpGame.test.js │ ├── backtrackingJumpGame.js │ ├── dpBottomUpJumpGame.js │ ├── dpTopDownJumpGame.js │ └── greedyJumpGame.js │ ├── knight-tour │ ├── README.md │ ├── __test__ │ │ └── knightTour.test.js │ └── knightTour.js │ ├── n-queens │ ├── QueenPosition.js │ ├── README.md │ ├── __test__ │ │ ├── QueensPosition.test.js │ │ ├── nQueens.test.js │ │ └── nQueensBitwise.test.js │ ├── nQueens.js │ └── nQueensBitwise.js │ ├── rain-terraces │ ├── README.md │ ├── __test__ │ │ ├── bfRainTerraces.test.js │ │ └── dpRainTerraces.test.js │ ├── bfRainTerraces.js │ └── dpRainTerraces.js │ ├── recursive-staircase │ ├── README.md │ ├── __test__ │ │ ├── recursiveStaircaseBF.test.js │ │ ├── recursiveStaircaseDP.test.js │ │ ├── recursiveStaircaseIT.test.js │ │ └── recursiveStaircaseMEM.test.js │ ├── recursiveStaircaseBF.js │ ├── recursiveStaircaseDP.js │ ├── recursiveStaircaseIT.js │ └── recursiveStaircaseMEM.js │ ├── square-matrix-rotation │ ├── README.md │ ├── __test__ │ │ └── squareMatrixRotation.test.js │ └── squareMatrixRotation.js │ └── unique-paths │ ├── README.md │ ├── __test__ │ ├── btUniquePaths.test.js │ ├── dpUniquePaths.test.js │ └── uniquePaths.test.js │ ├── btUniquePaths.js │ ├── dpUniquePaths.js │ └── uniquePaths.js ├── data-structures ├── bloom-filter │ ├── BloomFilter.js │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ └── __test__ │ │ └── BloomFilter.test.js ├── disjoint-set │ ├── DisjointSet.js │ ├── DisjointSetAdhoc.js │ ├── DisjointSetItem.js │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ └── __test__ │ │ ├── DisjointSet.test.js │ │ ├── DisjointSetAdhoc.test.js │ │ └── DisjointSetItem.test.js ├── doubly-linked-list │ ├── DoublyLinkedList.js │ ├── DoublyLinkedListNode.js │ ├── README.es-ES.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ ├── __test__ │ │ ├── DoublyLinkedList.test.js │ │ └── DoublyLinkedListNode.test.js │ └── images │ │ └── doubly-linked-list.jpeg ├── graph │ ├── Graph.js │ ├── GraphEdge.js │ ├── GraphVertex.js │ ├── README.fr-FR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ ├── __test__ │ │ ├── Graph.test.js │ │ ├── GraphEdge.test.js │ │ └── GraphVertex.test.js │ └── images │ │ └── graph.jpeg ├── hash-table │ ├── HashTable.js │ ├── README.fr-FR.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ ├── __test__ │ │ └── HashTable.test.js │ └── images │ │ ├── collision-resolution.jpeg │ │ └── hash-table.jpeg ├── heap │ ├── Heap.js │ ├── MaxHeap.js │ ├── MaxHeapAdhoc.js │ ├── MinHeap.js │ ├── MinHeapAdhoc.js │ ├── README.fr-FR.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.tr-TR.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ ├── __test__ │ │ ├── Heap.test.js │ │ ├── MaxHeap.test.js │ │ ├── MaxHeapAdhoc.test.js │ │ ├── MinHeap.test.js │ │ └── MinHeapAdhoc.test.js │ └── images │ │ ├── array-representation.jpeg │ │ ├── max-heap.jpeg │ │ └── min-heap.jpeg ├── linked-list │ ├── LinkedList.js │ ├── LinkedListNode.js │ ├── README.es-ES.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.tr-TR.md │ ├── README.uk-UA.md │ ├── README.vi-VN.md │ ├── README.zh-CN.md │ ├── __test__ │ │ ├── LinkedList.test.js │ │ └── LinkedListNode.test.js │ └── images │ │ └── linked-list.jpeg ├── lru-cache │ ├── LRUCache.js │ ├── LRUCacheOnMap.js │ ├── README.ko-KR.md │ ├── README.md │ ├── __test__ │ │ ├── LRUCache.test.js │ │ └── LRUCacheOnMap.test.js │ └── images │ │ └── lru-cache.jpg ├── priority-queue │ ├── PriorityQueue.js │ ├── README.fr-FR.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ └── __test__ │ │ └── PriorityQueue.test.js ├── queue │ ├── Queue.js │ ├── README.fr-FR.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.vi-VN.md │ ├── README.zh-CN.md │ ├── __test__ │ │ └── Queue.test.js │ └── images │ │ └── queue.jpeg ├── stack │ ├── README.fr-FR.md │ ├── README.ja-JP.md │ ├── README.ko-KR.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.vi-VN.md │ ├── README.zh-CN.md │ ├── Stack.js │ ├── __test__ │ │ └── Stack.test.js │ └── images │ │ ├── stack.jpeg │ │ └── stack.jpg ├── tree │ ├── BinaryTreeNode.js │ ├── README.md │ ├── README.pt-BR.md │ ├── README.zh-CN.md │ ├── __test__ │ │ └── BinaryTreeNode.test.js │ ├── avl-tree │ │ ├── AvlTree.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── AvlTRee.test.js │ ├── binary-search-tree │ │ ├── BinarySearchTree.js │ │ ├── BinarySearchTreeNode.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── __test__ │ │ │ ├── BinarySearchTree.test.js │ │ │ └── BinarySearchTreeNode.test.js │ │ └── images │ │ │ └── binary-search-tree.jpg │ ├── fenwick-tree │ │ ├── FenwickTree.js │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ └── __test__ │ │ │ └── FenwickTree.test.js │ ├── images │ │ └── tree.jpeg │ ├── red-black-tree │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── RedBlackTree.js │ │ └── __test__ │ │ │ └── RedBlackTree.test.js │ └── segment-tree │ │ ├── README.md │ │ ├── README.pt-BR.md │ │ ├── SegmentTree.js │ │ └── __test__ │ │ └── SegmentTree.test.js └── trie │ ├── README.ko-KO.md │ ├── README.md │ ├── README.pt-BR.md │ ├── README.ru-RU.md │ ├── README.uk-UA.md │ ├── README.zh-CN.md │ ├── Trie.js │ ├── TrieNode.js │ ├── __test__ │ ├── Trie.test.js │ └── TrieNode.test.js │ └── images │ └── trie.jpg ├── playground ├── README.md ├── __test__ │ └── playground.test.js └── playground.js └── utils └── comparator ├── Comparator.js └── __test__ └── Comparator.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # @see: https://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | quote_type = single 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": "airbnb", 4 | "plugins": ["jest"], 5 | "env": { 6 | "jest/globals": true 7 | }, 8 | "rules": { 9 | "no-bitwise": "off", 10 | "no-lonely-if": "off", 11 | "class-methods-use-this": "off", 12 | "arrow-body-style": "off", 13 | "no-loop-func": "off" 14 | }, 15 | "ignorePatterns": ["*.md", "*.png", "*.jpeg", "*.jpg"], 16 | "settings": { 17 | "react": { 18 | "version": "18.2.0" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # @see: https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository 2 | github: trekhleb 3 | patreon: trekhleb 4 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node-version: [ 16.x ] 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v2 19 | 20 | - name: Setup Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | 25 | - name: Install dependencies 26 | run: npm i 27 | 28 | - name: Run linting 29 | run: npm run lint 30 | 31 | - name: Run tests 32 | run: npm run coverage 33 | 34 | - name: Upload coverage to Codecov 35 | uses: codecov/codecov-action@v1 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | coverage 4 | .vscode 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | # npm run test 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.15.0 2 | -------------------------------------------------------------------------------- /BACKERS.md: -------------------------------------------------------------------------------- 1 | # Project Backers 2 | 3 | > You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). 4 | 5 | ## `O(2ⁿ)` Backers 6 | 7 | `null` 8 | 9 | ## `O(n²)` Backers 10 | 11 | `null` 12 | 13 | ## `O(n×log(n))` Backers 14 | 15 | `null` 16 | 17 | 34 | 35 | 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | **General Rules** 4 | 5 | - As much as possible, try to follow the existing format of markdown and code. 6 | - Don't forget to run `npm run lint` and `npm test` before submitting pull requests. 7 | - Make sure that **100%** of your code is covered by tests. 8 | 9 | **Contributing New Translation** 10 | 11 | - Create new `README.xx-XX.md` file with translation alongside with 12 | main `README.md` file where `xx-XX` is [locale and country/region codes](http://www.lingoes.net/en/translator/langcode.htm). 13 | For example `en-US`, `zh-CN`, `zh-TW`, `ko-KR` etc. 14 | - You may also translate all other sub-folders by creating 15 | related `README.xx-XX.md` files in each of them. 16 | 17 | **Contributing New Algorithms** 18 | 19 | - Make your pull requests to be **specific** and **focused**. Instead of 20 | contributing "several sorting algorithms" all at once contribute them all 21 | one by one separately (i.e. one pull request for "Quick Sort", another one 22 | for "Heap Sort" and so on). 23 | - Provide **README.md** for each of the algorithms **with explanations** of 24 | the algorithm and **with links** to further readings. 25 | - Describe what you do in code using **comments**. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Oleksii Trekhleb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/big-o-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/assets/big-o-graph.png -------------------------------------------------------------------------------- /src/algorithms/graph/articulation-points/README.md: -------------------------------------------------------------------------------- 1 | # Articulation Points (or Cut Vertices) 2 | 3 | A vertex in an undirected connected graph is an articulation point 4 | (or cut vertex) if removing it (and edges through it) disconnects 5 | the graph. Articulation points represent vulnerabilities in a 6 | connected network – single points whose failure would split the 7 | network into 2 or more disconnected components. They are useful for 8 | designing reliable networks. 9 | 10 | For a disconnected undirected graph, an articulation point is a 11 | vertex removing which increases number of connected components. 12 | 13 | ![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints.png) 14 | 15 | ![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints1.png) 16 | 17 | ![Articulation Points](https://www.geeksforgeeks.org/wp-content/uploads/ArticulationPoints21.png) 18 | 19 | ## References 20 | 21 | - [GeeksForGeeks](https://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/) 22 | - [YouTube](https://www.youtube.com/watch?v=2kREIkF9UAs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/algorithms/graph/bellman-ford/README.md: -------------------------------------------------------------------------------- 1 | # Bellman–Ford Algorithm 2 | 3 | The Bellman–Ford algorithm is an algorithm that computes shortest 4 | paths from a single source vertex to all of the other vertices 5 | in a weighted digraph. It is slower than Dijkstra's algorithm 6 | for the same problem, but more versatile, as it is capable of 7 | handling graphs in which some of the edge weights are negative 8 | numbers. 9 | 10 | ![Bellman-Ford](https://upload.wikimedia.org/wikipedia/commons/2/2e/Shortest_path_Dijkstra_vs_BellmanFord.gif) 11 | 12 | ## Complexity 13 | 14 | Worst-case performance `O(|V||E|)` 15 | Best-case performance `O(|E|)` 16 | Worst-case space complexity `O(|V|)` 17 | 18 | ## References 19 | 20 | - [Wikipedia](https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm) 21 | - [On YouTube by Michael Sambol](https://www.youtube.com/watch?v=obWXjtg0L64&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 22 | -------------------------------------------------------------------------------- /src/algorithms/graph/breadth-first-search/README.md: -------------------------------------------------------------------------------- 1 | # Breadth-First Search (BFS) 2 | 3 | Breadth-first search (BFS) is an algorithm for traversing, 4 | searching tree, or graph data structures. It starts at 5 | the tree root (or some arbitrary node of a graph, sometimes 6 | referred to as a 'search key') and explores the neighbor 7 | nodes first, before moving to the next level neighbors. 8 | 9 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif) 10 | 11 | ## References 12 | 13 | - [Wikipedia](https://en.wikipedia.org/wiki/Breadth-first_search) 14 | - [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/) 15 | - [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/) 16 | - [BFS Visualization](https://www.cs.usfca.edu/~galles/visualization/BFS.html) 17 | -------------------------------------------------------------------------------- /src/algorithms/graph/depth-first-search/README.md: -------------------------------------------------------------------------------- 1 | # Depth-First Search (DFS) 2 | 3 | Depth-first search (DFS) is an algorithm for traversing or 4 | searching tree or graph data structures. One starts at 5 | the root (selecting some arbitrary node as the root in 6 | the case of a graph) and explores as far as possible 7 | along each branch before backtracking. 8 | 9 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif) 10 | 11 | ## References 12 | 13 | - [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search) 14 | - [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/) 15 | - [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/) 16 | - [DFS Visualization](https://www.cs.usfca.edu/~galles/visualization/DFS.html) 17 | -------------------------------------------------------------------------------- /src/algorithms/graph/dijkstra/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # 다익스트라 알고리즘(Dijkstra's algorithm) 2 | 3 | 다익스트라 알고리즘은 도로 네트워크 등을 나타낼 수 있는 그래프에서 노드 간의 최단 경로를 찾는 알고리즘입니다. 4 | 5 | 이 알고리즘은 다양한 형태로 존재합니다. 다익스트라의 원래 형태는 두 노드 간의 최단 경로를 찾았지만, 더 일반적인 형태는 단일 노드를 "소스"노드로 수정하고 그래프의 소스에서 다른 모든 노드까지의 최단 경로를 찾아 최단 경로 트리(shortest-path tree)를 생성합니다. 6 | 7 | ![Dijkstra](https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif) 8 | 9 | `a`와 `b` 사이의 최단 경로를 찾는 다익스트라 알고리즘입니다. 10 | 가장 낮은 거리를 가지며 방문하지 않은 정점(vertex)를 선택하고, 이를 통해 방문하지 않은 각 이웃까지의 거리를 계산하며, 더 작은 경우 이웃의 거리를 업데이트합니다. 이웃에 대한 작업을 마치면 방문한 것으로 표시(빨간색으로 변경)합니다. 11 | 12 | ## 참조 13 | 14 | - [Wikipedia](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) 15 | - [On YouTube by Nathaniel Fan](https://www.youtube.com/watch?v=gdmfOwyQlcI&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 16 | - [On YouTube by Tushar Roy](https://www.youtube.com/watch?v=lAXZGERcDf4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 17 | -------------------------------------------------------------------------------- /src/algorithms/graph/strongly-connected-components/README.md: -------------------------------------------------------------------------------- 1 | # Strongly Connected Component 2 | 3 | A directed graph is called **strongly connected** if there is a path 4 | in each direction between each pair of vertices of the graph. 5 | In a directed graph G that may not itself be strongly connected, 6 | a pair of vertices `u` and `v` are said to be strongly connected 7 | to each other if there is a path in each direction between them. 8 | 9 | ![Strongly Connected](https://upload.wikimedia.org/wikipedia/commons/5/5c/Scc.png) 10 | 11 | Graph with strongly connected components marked 12 | 13 | ## References 14 | 15 | - [Wikipedia](https://en.wikipedia.org/wiki/Strongly_connected_component) 16 | - [YouTube](https://www.youtube.com/watch?v=RpgcYiky7uw&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 17 | -------------------------------------------------------------------------------- /src/algorithms/image-processing/seam-carving/__tests__/test-image-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/image-processing/seam-carving/__tests__/test-image-after.png -------------------------------------------------------------------------------- /src/algorithms/image-processing/seam-carving/__tests__/test-image-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/image-processing/seam-carving/__tests__/test-image-before.png -------------------------------------------------------------------------------- /src/algorithms/linked-list/reverse-traversal/README.md: -------------------------------------------------------------------------------- 1 | # Reversed Linked List Traversal 2 | 3 | _Read this in other languages:_ 4 | [_中文_](README.zh-CN.md), 5 | [_Português_](README.pt-BR.md) 6 | 7 | The task is to traverse the given linked list in reversed order. 8 | 9 | For example for the following linked list: 10 | 11 | ![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 12 | 13 | The order of traversal should be: 14 | 15 | ```text 16 | 37 → 99 → 12 17 | ``` 18 | 19 | The time complexity is `O(n)` because we visit every node only once. 20 | 21 | ## Reference 22 | 23 | - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) 24 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/reverse-traversal/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Travessia de Lista Encadeada Reversa 2 | 3 | _Leia isso em outros idiomas:_ 4 | [_中文_](README.zh-CN.md), 5 | [_English_](README.md) 6 | 7 | A tarefa é percorrer a lista encadeada fornecida em ordem inversa. 8 | 9 | Por exemplo, para a seguinte lista vinculada: 10 | 11 | ![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 12 | 13 | A ordem de travessia deve ser: 14 | 15 | ```texto 16 | 37 → 99 → 12 17 | ``` 18 | 19 | A complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez. 20 | 21 | ## Referência 22 | 23 | - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) 24 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/reverse-traversal/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 链表倒序遍历 2 | 3 | 我们的任务是倒序遍历给定的链表 4 | 5 | 比如下面的链表 6 | 7 | ![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 8 | 9 | 遍历的顺序应该是 10 | 11 | ```text 12 | 37 → 99 → 12 13 | ``` 14 | 15 | 因为我们每个节点只访问一次,时间复杂度应该是`O(n)` 16 | 17 | ## 参考 18 | 19 | - [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8) 20 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/reverse-traversal/__test__/reverseTraversal.test.js: -------------------------------------------------------------------------------- 1 | import LinkedList from '../../../../data-structures/linked-list/LinkedList'; 2 | import reverseTraversal from '../reverseTraversal'; 3 | 4 | describe('reverseTraversal', () => { 5 | it('should traverse linked list in reverse order', () => { 6 | const linkedList = new LinkedList(); 7 | 8 | linkedList 9 | .append(1) 10 | .append(2) 11 | .append(3); 12 | 13 | const traversedNodeValues = []; 14 | const traversalCallback = (nodeValue) => { 15 | traversedNodeValues.push(nodeValue); 16 | }; 17 | 18 | reverseTraversal(linkedList, traversalCallback); 19 | 20 | expect(traversedNodeValues).toEqual([3, 2, 1]); 21 | }); 22 | }); 23 | 24 | // it('should reverse traversal the linked list with callback', () => { 25 | // const linkedList = new LinkedList(); 26 | // 27 | // linkedList 28 | // .append(1) 29 | // .append(2) 30 | // .append(3); 31 | // 32 | // expect(linkedList.toString()).toBe('1,2,3'); 33 | // expect(linkedList.reverseTraversal(linkedList.head, value => value * 2)).toEqual([6, 4, 2]); 34 | // expect(() => linkedList.reverseTraversal(linkedList.head)).toThrow(); 35 | // }); 36 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/reverse-traversal/reverseTraversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Traversal callback function. 3 | * @callback traversalCallback 4 | * @param {*} nodeValue 5 | */ 6 | 7 | /** 8 | * @param {LinkedListNode} node 9 | * @param {traversalCallback} callback 10 | */ 11 | function reverseTraversalRecursive(node, callback) { 12 | if (node) { 13 | reverseTraversalRecursive(node.next, callback); 14 | callback(node.value); 15 | } 16 | } 17 | 18 | /** 19 | * @param {LinkedList} linkedList 20 | * @param {traversalCallback} callback 21 | */ 22 | export default function reverseTraversal(linkedList, callback) { 23 | reverseTraversalRecursive(linkedList.head, callback); 24 | } 25 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/README.md: -------------------------------------------------------------------------------- 1 | # Linked List Traversal 2 | 3 | _Read this in other languages:_ 4 | [_Русский_](README.ru-RU.md), 5 | [_中文_](README.zh-CN.md), 6 | [_Português_](README.pt-BR.md) 7 | 8 | The task is to traverse the given linked list in straight order. 9 | 10 | For example for the following linked list: 11 | 12 | ![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 13 | 14 | The order of traversal should be: 15 | 16 | ```text 17 | 12 → 99 → 37 18 | ``` 19 | 20 | The time complexity is `O(n)` because we visit every node only once. 21 | 22 | ## Reference 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) 25 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Travessia de Lista Encadeada 2 | 3 | _Leia isso em outros idiomas:_ 4 | [_Русский_](README.ru-RU.md), 5 | [_中文_](README.zh-CN.md), 6 | [_English_](README.md) 7 | 8 | A tarefa é percorrer a lista encadeada fornecida em ordem direta. 9 | 10 | Por exemplo, para a seguinte lista vinculada: 11 | 12 | ![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 13 | 14 | A ordem de travessia deve ser: 15 | 16 | ```texto 17 | 12 → 99 → 37 18 | ``` 19 | 20 | A complexidade de tempo é `O(n)` porque visitamos cada nó apenas uma vez. 21 | 22 | ## Referência 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) 25 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/README.ru-RU.md: -------------------------------------------------------------------------------- 1 | # Обход связного списка 2 | 3 | Задача состоит в том, чтобы обойти связный список в прямом порядке. 4 | 5 | Например, для следующего связного списка: 6 | 7 | ![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 8 | 9 | Порядок обхода будет такой: 10 | 11 | ```text 12 | 12 → 99 → 37 13 | ``` 14 | 15 | Временная сложность - `O(n)`, потому что мы посещаем каждый узел только один раз. 16 | 17 | ## Ссылки 18 | 19 | - [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA) 20 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 链表遍历 2 | 3 | 我们的任务是顺序遍历给定的链表 4 | 5 | 比如下面的链表 6 | 7 | ![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) 8 | 9 | 遍历的顺序应该是 10 | 11 | ```text 12 | 12 → 99 → 37 13 | ``` 14 | 15 | 因为我们每个节点只访问一次,时间复杂度应该是`O(n)` 16 | 17 | ## 参考 18 | 19 | - [Wikipedia](https://zh.wikipedia.org/wiki/%E9%93%BE%E8%A1%A8) -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/__test__/traversal.test.js: -------------------------------------------------------------------------------- 1 | import LinkedList from '../../../../data-structures/linked-list/LinkedList'; 2 | import traversal from '../traversal'; 3 | 4 | describe('traversal', () => { 5 | it('should traverse linked list', () => { 6 | const linkedList = new LinkedList(); 7 | 8 | linkedList 9 | .append(1) 10 | .append(2) 11 | .append(3); 12 | 13 | const traversedNodeValues = []; 14 | const traversalCallback = (nodeValue) => { 15 | traversedNodeValues.push(nodeValue); 16 | }; 17 | 18 | traversal(linkedList, traversalCallback); 19 | 20 | expect(traversedNodeValues).toEqual([1, 2, 3]); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/algorithms/linked-list/traversal/traversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Traversal callback function. 3 | * @callback traversalCallback 4 | * @param {*} nodeValue 5 | */ 6 | 7 | /** 8 | * @param {LinkedList} linkedList 9 | * @param {traversalCallback} callback 10 | */ 11 | export default function traversal(linkedList, callback) { 12 | let currentNode = linkedList.head; 13 | 14 | while (currentNode) { 15 | callback(currentNode.value); 16 | currentNode = currentNode.next; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js: -------------------------------------------------------------------------------- 1 | import { floatAs32BinaryString, floatAs64BinaryString } from '../floatAsBinaryString'; 2 | import { testCases32Bits, testCases64Bits } from '../testCases'; 3 | 4 | describe('floatAs32Binary', () => { 5 | it('should create a binary representation of the floating numbers', () => { 6 | for (let testCaseIndex = 0; testCaseIndex < testCases32Bits.length; testCaseIndex += 1) { 7 | const [decimal, binary] = testCases32Bits[testCaseIndex]; 8 | expect(floatAs32BinaryString(decimal)).toBe(binary); 9 | } 10 | }); 11 | }); 12 | 13 | describe('floatAs64Binary', () => { 14 | it('should create a binary representation of the floating numbers', () => { 15 | for (let testCaseIndex = 0; testCaseIndex < testCases64Bits.length; testCaseIndex += 1) { 16 | const [decimal, binary] = testCases64Bits[testCaseIndex]; 17 | expect(floatAs64BinaryString(decimal)).toBe(binary); 18 | } 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/algorithms/math/binary-floating-point/images/02-half-precision-floating-point-number-explained.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/math/binary-floating-point/images/02-half-precision-floating-point-number-explained.png -------------------------------------------------------------------------------- /src/algorithms/math/binary-floating-point/images/03-scientific-notation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/math/binary-floating-point/images/03-scientific-notation.png -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/bitLength.test.js: -------------------------------------------------------------------------------- 1 | import bitLength from '../bitLength'; 2 | 3 | describe('bitLength', () => { 4 | it('should calculate number of bits that the number is consists of', () => { 5 | expect(bitLength(0b0)).toBe(0); 6 | expect(bitLength(0b1)).toBe(1); 7 | expect(bitLength(0b01)).toBe(1); 8 | expect(bitLength(0b101)).toBe(3); 9 | expect(bitLength(0b0101)).toBe(3); 10 | expect(bitLength(0b10101)).toBe(5); 11 | expect(bitLength(0b11110101)).toBe(8); 12 | expect(bitLength(0b00011110101)).toBe(8); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/bitsDiff.test.js: -------------------------------------------------------------------------------- 1 | import bitsDiff from '../bitsDiff'; 2 | 3 | describe('bitsDiff', () => { 4 | it('should calculate bits difference between two numbers', () => { 5 | expect(bitsDiff(0, 0)).toBe(0); 6 | expect(bitsDiff(1, 1)).toBe(0); 7 | expect(bitsDiff(124, 124)).toBe(0); 8 | expect(bitsDiff(0, 1)).toBe(1); 9 | expect(bitsDiff(1, 0)).toBe(1); 10 | expect(bitsDiff(1, 2)).toBe(2); 11 | expect(bitsDiff(1, 3)).toBe(1); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/clearBit.test.js: -------------------------------------------------------------------------------- 1 | import clearBit from '../clearBit'; 2 | 3 | describe('clearBit', () => { 4 | it('should clear bit at specific position', () => { 5 | // 1 = 0b0001 6 | expect(clearBit(1, 0)).toBe(0); 7 | expect(clearBit(1, 1)).toBe(1); 8 | expect(clearBit(1, 2)).toBe(1); 9 | 10 | // 10 = 0b1010 11 | expect(clearBit(10, 0)).toBe(10); 12 | expect(clearBit(10, 1)).toBe(8); 13 | expect(clearBit(10, 3)).toBe(2); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/countSetBits.test.js: -------------------------------------------------------------------------------- 1 | import countSetBits from '../countSetBits'; 2 | 3 | describe('countSetBits', () => { 4 | it('should return number of set bits', () => { 5 | expect(countSetBits(0)).toBe(0); 6 | expect(countSetBits(1)).toBe(1); 7 | expect(countSetBits(2)).toBe(1); 8 | expect(countSetBits(3)).toBe(2); 9 | expect(countSetBits(4)).toBe(1); 10 | expect(countSetBits(5)).toBe(2); 11 | expect(countSetBits(21)).toBe(3); 12 | expect(countSetBits(255)).toBe(8); 13 | expect(countSetBits(1023)).toBe(10); 14 | expect(countSetBits(-1)).toBe(32); 15 | expect(countSetBits(-21)).toBe(30); 16 | expect(countSetBits(-255)).toBe(25); 17 | expect(countSetBits(-1023)).toBe(23); 18 | expect(countSetBits(-4294967296)).toBe(0); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/divideByTwo.test.js: -------------------------------------------------------------------------------- 1 | import divideByTwo from '../divideByTwo'; 2 | 3 | describe('divideByTwo', () => { 4 | it('should divide numbers by two using bitwise operations', () => { 5 | expect(divideByTwo(0)).toBe(0); 6 | expect(divideByTwo(1)).toBe(0); 7 | expect(divideByTwo(3)).toBe(1); 8 | expect(divideByTwo(10)).toBe(5); 9 | expect(divideByTwo(17)).toBe(8); 10 | expect(divideByTwo(125)).toBe(62); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/fullAdder.test.js: -------------------------------------------------------------------------------- 1 | import fullAdder from '../fullAdder'; 2 | 3 | describe('fullAdder', () => { 4 | it('should add up two numbers', () => { 5 | expect(fullAdder(0, 0)).toBe(0); 6 | expect(fullAdder(2, 0)).toBe(2); 7 | expect(fullAdder(0, 2)).toBe(2); 8 | expect(fullAdder(1, 2)).toBe(3); 9 | expect(fullAdder(2, 1)).toBe(3); 10 | expect(fullAdder(6, 6)).toBe(12); 11 | expect(fullAdder(-2, 4)).toBe(2); 12 | expect(fullAdder(4, -2)).toBe(2); 13 | expect(fullAdder(-4, -4)).toBe(-8); 14 | expect(fullAdder(4, -5)).toBe(-1); 15 | expect(fullAdder(2, 121)).toBe(123); 16 | expect(fullAdder(121, 2)).toBe(123); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/getBit.test.js: -------------------------------------------------------------------------------- 1 | import getBit from '../getBit'; 2 | 3 | describe('getBit', () => { 4 | it('should get bit at specific position', () => { 5 | // 1 = 0b0001 6 | expect(getBit(1, 0)).toBe(1); 7 | expect(getBit(1, 1)).toBe(0); 8 | 9 | // 2 = 0b0010 10 | expect(getBit(2, 0)).toBe(0); 11 | expect(getBit(2, 1)).toBe(1); 12 | 13 | // 3 = 0b0011 14 | expect(getBit(3, 0)).toBe(1); 15 | expect(getBit(3, 1)).toBe(1); 16 | 17 | // 10 = 0b1010 18 | expect(getBit(10, 0)).toBe(0); 19 | expect(getBit(10, 1)).toBe(1); 20 | expect(getBit(10, 2)).toBe(0); 21 | expect(getBit(10, 3)).toBe(1); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/isEven.test.js: -------------------------------------------------------------------------------- 1 | import isEven from '../isEven'; 2 | 3 | describe('isEven', () => { 4 | it('should detect if a number is even', () => { 5 | expect(isEven(0)).toBe(true); 6 | expect(isEven(2)).toBe(true); 7 | expect(isEven(-2)).toBe(true); 8 | expect(isEven(1)).toBe(false); 9 | expect(isEven(-1)).toBe(false); 10 | expect(isEven(-3)).toBe(false); 11 | expect(isEven(3)).toBe(false); 12 | expect(isEven(8)).toBe(true); 13 | expect(isEven(9)).toBe(false); 14 | expect(isEven(121)).toBe(false); 15 | expect(isEven(122)).toBe(true); 16 | expect(isEven(1201)).toBe(false); 17 | expect(isEven(1202)).toBe(true); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/isPositive.test.js: -------------------------------------------------------------------------------- 1 | import isPositive from '../isPositive'; 2 | 3 | describe('isPositive', () => { 4 | it('should detect if a number is positive', () => { 5 | expect(isPositive(1)).toBe(true); 6 | expect(isPositive(2)).toBe(true); 7 | expect(isPositive(3)).toBe(true); 8 | expect(isPositive(5665)).toBe(true); 9 | expect(isPositive(56644325)).toBe(true); 10 | 11 | expect(isPositive(0)).toBe(false); 12 | expect(isPositive(-0)).toBe(false); 13 | expect(isPositive(-1)).toBe(false); 14 | expect(isPositive(-2)).toBe(false); 15 | expect(isPositive(-126)).toBe(false); 16 | expect(isPositive(-5665)).toBe(false); 17 | expect(isPositive(-56644325)).toBe(false); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/isPowerOfTwo.test.js: -------------------------------------------------------------------------------- 1 | import isPowerOfTwo from '../isPowerOfTwo'; 2 | 3 | describe('isPowerOfTwo', () => { 4 | it('should detect if the number is power of two', () => { 5 | expect(isPowerOfTwo(1)).toBe(true); 6 | expect(isPowerOfTwo(2)).toBe(true); 7 | expect(isPowerOfTwo(3)).toBe(false); 8 | expect(isPowerOfTwo(4)).toBe(true); 9 | expect(isPowerOfTwo(5)).toBe(false); 10 | expect(isPowerOfTwo(6)).toBe(false); 11 | expect(isPowerOfTwo(7)).toBe(false); 12 | expect(isPowerOfTwo(8)).toBe(true); 13 | expect(isPowerOfTwo(9)).toBe(false); 14 | expect(isPowerOfTwo(16)).toBe(true); 15 | expect(isPowerOfTwo(23)).toBe(false); 16 | expect(isPowerOfTwo(32)).toBe(true); 17 | expect(isPowerOfTwo(127)).toBe(false); 18 | expect(isPowerOfTwo(128)).toBe(true); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/multiply.test.js: -------------------------------------------------------------------------------- 1 | import multiply from '../multiply'; 2 | 3 | describe('multiply', () => { 4 | it('should multiply two numbers', () => { 5 | expect(multiply(0, 0)).toBe(0); 6 | expect(multiply(2, 0)).toBe(0); 7 | expect(multiply(0, 2)).toBe(0); 8 | expect(multiply(1, 2)).toBe(2); 9 | expect(multiply(2, 1)).toBe(2); 10 | expect(multiply(6, 6)).toBe(36); 11 | expect(multiply(-2, 4)).toBe(-8); 12 | expect(multiply(4, -2)).toBe(-8); 13 | expect(multiply(-4, -4)).toBe(16); 14 | expect(multiply(4, -5)).toBe(-20); 15 | expect(multiply(2, 121)).toBe(242); 16 | expect(multiply(121, 2)).toBe(242); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/multiplyByTwo.test.js: -------------------------------------------------------------------------------- 1 | import multiplyByTwo from '../multiplyByTwo'; 2 | 3 | describe('multiplyByTwo', () => { 4 | it('should multiply numbers by two using bitwise operations', () => { 5 | expect(multiplyByTwo(0)).toBe(0); 6 | expect(multiplyByTwo(1)).toBe(2); 7 | expect(multiplyByTwo(3)).toBe(6); 8 | expect(multiplyByTwo(10)).toBe(20); 9 | expect(multiplyByTwo(17)).toBe(34); 10 | expect(multiplyByTwo(125)).toBe(250); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/multiplyUnsigned.test.js: -------------------------------------------------------------------------------- 1 | import multiplyUnsigned from '../multiplyUnsigned'; 2 | 3 | describe('multiplyUnsigned', () => { 4 | it('should multiply two unsigned numbers', () => { 5 | expect(multiplyUnsigned(0, 2)).toBe(0); 6 | expect(multiplyUnsigned(2, 0)).toBe(0); 7 | expect(multiplyUnsigned(1, 1)).toBe(1); 8 | expect(multiplyUnsigned(1, 2)).toBe(2); 9 | expect(multiplyUnsigned(2, 7)).toBe(14); 10 | expect(multiplyUnsigned(7, 2)).toBe(14); 11 | expect(multiplyUnsigned(30, 2)).toBe(60); 12 | expect(multiplyUnsigned(17, 34)).toBe(578); 13 | expect(multiplyUnsigned(170, 2340)).toBe(397800); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/setBit.test.js: -------------------------------------------------------------------------------- 1 | import setBit from '../setBit'; 2 | 3 | describe('setBit', () => { 4 | it('should set bit at specific position', () => { 5 | // 1 = 0b0001 6 | expect(setBit(1, 0)).toBe(1); 7 | expect(setBit(1, 1)).toBe(3); 8 | expect(setBit(1, 2)).toBe(5); 9 | 10 | // 10 = 0b1010 11 | expect(setBit(10, 0)).toBe(11); 12 | expect(setBit(10, 1)).toBe(10); 13 | expect(setBit(10, 2)).toBe(14); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/switchSign.test.js: -------------------------------------------------------------------------------- 1 | import switchSign from '../switchSign'; 2 | 3 | describe('switchSign', () => { 4 | it('should switch the sign of the number using twos complement approach', () => { 5 | expect(switchSign(0)).toBe(0); 6 | expect(switchSign(1)).toBe(-1); 7 | expect(switchSign(-1)).toBe(1); 8 | expect(switchSign(32)).toBe(-32); 9 | expect(switchSign(-32)).toBe(32); 10 | expect(switchSign(23)).toBe(-23); 11 | expect(switchSign(-23)).toBe(23); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/__test__/updateBit.test.js: -------------------------------------------------------------------------------- 1 | import updateBit from '../updateBit'; 2 | 3 | describe('updateBit', () => { 4 | it('should update bit at specific position', () => { 5 | // 1 = 0b0001 6 | expect(updateBit(1, 0, 1)).toBe(1); 7 | expect(updateBit(1, 0, 0)).toBe(0); 8 | expect(updateBit(1, 1, 1)).toBe(3); 9 | expect(updateBit(1, 2, 1)).toBe(5); 10 | 11 | // 10 = 0b1010 12 | expect(updateBit(10, 0, 1)).toBe(11); 13 | expect(updateBit(10, 0, 0)).toBe(10); 14 | expect(updateBit(10, 1, 1)).toBe(10); 15 | expect(updateBit(10, 1, 0)).toBe(8); 16 | expect(updateBit(10, 2, 1)).toBe(14); 17 | expect(updateBit(10, 2, 0)).toBe(10); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/bitLength.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Return the number of bits used in the binary representation of the number. 3 | * 4 | * @param {number} number 5 | * @return {number} 6 | */ 7 | export default function bitLength(number) { 8 | let bitsCounter = 0; 9 | 10 | while ((1 << bitsCounter) <= number) { 11 | bitsCounter += 1; 12 | } 13 | 14 | return bitsCounter; 15 | } 16 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/bitsDiff.js: -------------------------------------------------------------------------------- 1 | import countSetBits from './countSetBits'; 2 | 3 | /** 4 | * Counts the number of bits that need to be change in order 5 | * to convert numberA to numberB. 6 | * 7 | * @param {number} numberA 8 | * @param {number} numberB 9 | * @return {number} 10 | */ 11 | export default function bitsDiff(numberA, numberB) { 12 | return countSetBits(numberA ^ numberB); 13 | } 14 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/clearBit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @param {number} bitPosition - zero based. 4 | * @return {number} 5 | */ 6 | export default function clearBit(number, bitPosition) { 7 | const mask = ~(1 << bitPosition); 8 | 9 | return number & mask; 10 | } 11 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/countSetBits.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} originalNumber 3 | * @return {number} 4 | */ 5 | export default function countSetBits(originalNumber) { 6 | let setBitsCount = 0; 7 | let number = originalNumber; 8 | 9 | while (number) { 10 | // Add last bit of the number to the sum of set bits. 11 | setBitsCount += number & 1; 12 | 13 | // Shift number right by one bit to investigate other bits. 14 | number >>>= 1; 15 | } 16 | 17 | return setBitsCount; 18 | } 19 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/divideByTwo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {number} 4 | */ 5 | export default function divideByTwo(number) { 6 | return number >> 1; 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/getBit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @param {number} bitPosition - zero based. 4 | * @return {number} 5 | */ 6 | export default function getBit(number, bitPosition) { 7 | return (number >> bitPosition) & 1; 8 | } 9 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/isEven.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {boolean} 4 | */ 5 | export default function isEven(number) { 6 | return (number & 1) === 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/isPositive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number - 32-bit integer. 3 | * @return {boolean} 4 | */ 5 | export default function isPositive(number) { 6 | // Zero is neither a positive nor a negative number. 7 | if (number === 0) { 8 | return false; 9 | } 10 | 11 | // The most significant 32nd bit can be used to determine whether the number is positive. 12 | return ((number >> 31) & 1) === 0; 13 | } 14 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/isPowerOfTwo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return bool 4 | */ 5 | export default function isPowerOfTwo(number) { 6 | return (number & (number - 1)) === 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/multiplyByTwo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {number} 4 | */ 5 | export default function multiplyByTwo(number) { 6 | return number << 1; 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/setBit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @param {number} bitPosition - zero based. 4 | * @return {number} 5 | */ 6 | export default function setBit(number, bitPosition) { 7 | return number | (1 << bitPosition); 8 | } 9 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/switchSign.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Switch the sign of the number using "Twos Complement" approach. 3 | * @param {number} number 4 | * @return {number} 5 | */ 6 | export default function switchSign(number) { 7 | return ~number + 1; 8 | } 9 | -------------------------------------------------------------------------------- /src/algorithms/math/bits/updateBit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @param {number} bitPosition - zero based. 4 | * @param {number} bitValue - 0 or 1. 5 | * @return {number} 6 | */ 7 | export default function updateBit(number, bitPosition, bitValue) { 8 | // Normalized bit value. 9 | const bitValueNormalized = bitValue ? 1 : 0; 10 | 11 | // Init clear mask. 12 | const clearMask = ~(1 << bitPosition); 13 | 14 | // Clear bit value and then set it up to required value. 15 | return (number & clearMask) | (bitValueNormalized << bitPosition); 16 | } 17 | -------------------------------------------------------------------------------- /src/algorithms/math/euclidean-algorithm/euclideanAlgorithm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Recursive version of Euclidean Algorithm of finding greatest common divisor (GCD). 3 | * @param {number} originalA 4 | * @param {number} originalB 5 | * @return {number} 6 | */ 7 | export default function euclideanAlgorithm(originalA, originalB) { 8 | // Make input numbers positive. 9 | const a = Math.abs(originalA); 10 | const b = Math.abs(originalB); 11 | 12 | // To make algorithm work faster instead of subtracting one number from the other 13 | // we may use modulo operation. 14 | return (b === 0) ? a : euclideanAlgorithm(b, a % b); 15 | } 16 | -------------------------------------------------------------------------------- /src/algorithms/math/euclidean-algorithm/euclideanAlgorithmIterative.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Iterative version of Euclidean Algorithm of finding greatest common divisor (GCD). 3 | * @param {number} originalA 4 | * @param {number} originalB 5 | * @return {number} 6 | */ 7 | export default function euclideanAlgorithmIterative(originalA, originalB) { 8 | // Make input numbers positive. 9 | let a = Math.abs(originalA); 10 | let b = Math.abs(originalB); 11 | 12 | // Subtract one number from another until both numbers would become the same. 13 | // This will be out GCD. Also quit the loop if one of the numbers is zero. 14 | while (a && b && a !== b) { 15 | [a, b] = a > b ? [a - b, b] : [a, b - a]; 16 | } 17 | 18 | // Return the number that is not equal to zero since the last subtraction (it will be a GCD). 19 | return a || b; 20 | } 21 | -------------------------------------------------------------------------------- /src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js: -------------------------------------------------------------------------------- 1 | import euclideanDistance from '../euclideanDistance'; 2 | 3 | describe('euclideanDistance', () => { 4 | it('should calculate euclidean distance between vectors', () => { 5 | expect(euclideanDistance([[1]], [[2]])).toEqual(1); 6 | expect(euclideanDistance([[2]], [[1]])).toEqual(1); 7 | expect(euclideanDistance([[5, 8]], [[7, 3]])).toEqual(5.39); 8 | expect(euclideanDistance([[5], [8]], [[7], [3]])).toEqual(5.39); 9 | expect(euclideanDistance([[8, 2, 6]], [[3, 5, 7]])).toEqual(5.92); 10 | expect(euclideanDistance([[8], [2], [6]], [[3], [5], [7]])).toEqual(5.92); 11 | expect(euclideanDistance([[[8]], [[2]], [[6]]], [[[3]], [[5]], [[7]]])).toEqual(5.92); 12 | }); 13 | 14 | it('should throw an error in case if two matrices are of different shapes', () => { 15 | expect(() => euclideanDistance([[1]], [[[2]]])).toThrowError( 16 | 'Matrices have different dimensions', 17 | ); 18 | 19 | expect(() => euclideanDistance([[1]], [[2, 3]])).toThrowError( 20 | 'Matrices have different shapes', 21 | ); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/euclidean-distance/euclideanDistance.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('../matrix/Matrix.js').Matrix} Matrix 3 | */ 4 | 5 | import * as mtrx from '../matrix/Matrix'; 6 | 7 | /** 8 | * Calculates the euclidean distance between 2 matrices. 9 | * 10 | * @param {Matrix} a 11 | * @param {Matrix} b 12 | * @returns {number} 13 | * @trows {Error} 14 | */ 15 | const euclideanDistance = (a, b) => { 16 | mtrx.validateSameShape(a, b); 17 | 18 | let squaresTotal = 0; 19 | 20 | mtrx.walk(a, (indices, aCellValue) => { 21 | const bCellValue = mtrx.getCellAtIndex(b, indices); 22 | squaresTotal += (aCellValue - bCellValue) ** 2; 23 | }); 24 | 25 | return Number(Math.sqrt(squaresTotal).toFixed(2)); 26 | }; 27 | 28 | export default euclideanDistance; 29 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.fr-FR.md: -------------------------------------------------------------------------------- 1 | # Factorielle 2 | 3 | _Lisez ceci dans d'autres langues:_ 4 | [english](README.md), [_简体中文_](README.zh-CN.md). 5 | 6 | En mathématiques, la factorielle d'un entier naturel `n`, 7 | notée avec un point d'exclamation `n!`, est le produit des nombres entiers 8 | strictement positifs inférieurs ou égaux à n. Par exemple: 9 | 10 | ``` 11 | 5! = 5 * 4 * 3 * 2 * 1 = 120 12 | ``` 13 | 14 | | n | n! | 15 | | --- | ----------------: | 16 | | 0 | 1 | 17 | | 1 | 1 | 18 | | 2 | 2 | 19 | | 3 | 6 | 20 | | 4 | 24 | 21 | | 5 | 120 | 22 | | 6 | 720 | 23 | | 7 | 5 040 | 24 | | 8 | 40 320 | 25 | | 9 | 362 880 | 26 | | 10 | 3 628 800 | 27 | | 11 | 39 916 800 | 28 | | 12 | 479 001 600 | 29 | | 13 | 6 227 020 800 | 30 | | 14 | 87 178 291 200 | 31 | | 15 | 1 307 674 368 000 | 32 | 33 | ## References 34 | 35 | [Wikipedia](https://fr.wikipedia.org/wiki/Factorielle) 36 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.ka-GE.md: -------------------------------------------------------------------------------- 1 | # ფაქტორიალი 2 | 3 | მათემატიკაში `n` ნატურალური რიცხვის ფაქტორიალი 4 | (აღინიშნება `n!` სიმბოლოთი) 5 | არის ყველა ნატურალური რიცხვის ნამრავლი 1-იდან `n`-ის ჩათვლით. მაგალითად: 6 | 7 | ``` 8 | 5! = 5 * 4 * 3 * 2 * 1 = 120 9 | ``` 10 | 11 | | n | n! | 12 | | --- | ----------------: | 13 | | 0 | 1 | 14 | | 1 | 1 | 15 | | 2 | 2 | 16 | | 3 | 6 | 17 | | 4 | 24 | 18 | | 5 | 120 | 19 | | 6 | 720 | 20 | | 7 | 5 040 | 21 | | 8 | 40 320 | 22 | | 9 | 362 880 | 23 | | 10 | 3 628 800 | 24 | | 11 | 39 916 800 | 25 | | 12 | 479 001 600 | 26 | | 13 | 6 227 020 800 | 27 | | 14 | 87 178 291 200 | 28 | | 15 | 1 307 674 368 000 | 29 | 30 | ## სქოლიო 31 | 32 | [Wikipedia](https://ka.wikipedia.org/wiki/%E1%83%9B%E1%83%90%E1%83%97%E1%83%94%E1%83%9B%E1%83%90%E1%83%A2%E1%83%98%E1%83%99%E1%83%A3%E1%83%A0%E1%83%98_%E1%83%A4%E1%83%90%E1%83%A5%E1%83%A2%E1%83%9D%E1%83%A0%E1%83%98%E1%83%90%E1%83%9A%E1%83%98) 33 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.md: -------------------------------------------------------------------------------- 1 | # Factorial 2 | 3 | _Read this in other languages:_ 4 | [_简体中文_](README.zh-CN.md), [_Français_](README.fr-FR.md), [_Türkçe_](README.tr-TR.md), [_ქართული_](README.ka-GE.md), [_Українська_](README.uk-UA.md). 5 | 6 | In mathematics, the factorial of a non-negative integer `n`, 7 | denoted by `n!`, is the product of all positive integers less 8 | than or equal to `n`. For example: 9 | 10 | ``` 11 | 5! = 5 * 4 * 3 * 2 * 1 = 120 12 | ``` 13 | 14 | | n | n! | 15 | | --- | ----------------: | 16 | | 0 | 1 | 17 | | 1 | 1 | 18 | | 2 | 2 | 19 | | 3 | 6 | 20 | | 4 | 24 | 21 | | 5 | 120 | 22 | | 6 | 720 | 23 | | 7 | 5 040 | 24 | | 8 | 40 320 | 25 | | 9 | 362 880 | 26 | | 10 | 3 628 800 | 27 | | 11 | 39 916 800 | 28 | | 12 | 479 001 600 | 29 | | 13 | 6 227 020 800 | 30 | | 14 | 87 178 291 200 | 31 | | 15 | 1 307 674 368 000 | 32 | 33 | ## References 34 | 35 | [Wikipedia](https://en.wikipedia.org/wiki/Factorial) 36 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.tr-TR.md: -------------------------------------------------------------------------------- 1 | # Faktöriyel 2 | 3 | _Bunu diğer dillerde okuyun:_ 4 | [_简体中文_](README.zh-CN.md), [français](README.fr-FR.md). 5 | 6 | Faktöriyel, matematikte, sağına ünlem işareti konulmuş sayıya 7 | verilen isim, daha genel olan Gama fonksiyonunun tam sayılarla 8 | sınırlanmış özel bir durumudur. 1'den başlayarak belirli bir 9 | sayma sayısına kadar olan sayıların çarpımına o sayının 10 | faktöriyeli denir. Basit bir şekilde faktöriyel, n tane ayrık 11 | elemanın kaç farklı şekilde sıralanabileceğidir. 12 | 13 | ``` 14 | 5! = 5 * 4 * 3 * 2 * 1 = 120 15 | ``` 16 | 17 | | n | n! | 18 | | --- | ----------------: | 19 | | 0 | 1 | 20 | | 1 | 1 | 21 | | 2 | 2 | 22 | | 3 | 6 | 23 | | 4 | 24 | 24 | | 5 | 120 | 25 | | 6 | 720 | 26 | | 7 | 5 040 | 27 | | 8 | 40 320 | 28 | | 9 | 362 880 | 29 | | 10 | 3 628 800 | 30 | | 11 | 39 916 800 | 31 | | 12 | 479 001 600 | 32 | | 13 | 6 227 020 800 | 33 | | 14 | 87 178 291 200 | 34 | | 15 | 1 307 674 368 000 | 35 | 36 | ## Referanslar 37 | 38 | [Wikipedia](https://en.wikipedia.org/wiki/Factorial) 39 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Факторіал 2 | 3 | _Прочитайте це іншими мовами:_ 4 | [_English_](README.md), [_简体中文_](README.zh-CN.md), [_Français_](README.fr-FR.md), [_Türkçe_](README.tr-TR.md), [_ქართული_](README.ka-GE.md). 5 | 6 | У математиці факторіал невід'ємного цілого числа `n`, позначений `n!`, є добутком усіх натуральних чисел, менших або рівних `n`. Наприклад: 7 | 8 | ``` 9 | 5! = 5 * 4 * 3 * 2 * 1 = 120 10 | ``` 11 | 12 | | n | n! | 13 | | --- | ----------------: | 14 | | 0 | 1 | 15 | | 1 | 1 | 16 | | 2 | 2 | 17 | | 3 | 6 | 18 | | 4 | 24 | 19 | | 5 | 120 | 20 | | 6 | 720 | 21 | | 7 | 5 040 | 22 | | 8 | 40 320 | 23 | | 9 | 362 880 | 24 | | 10 | 3 628 800 | 25 | | 11 | 39 916 800 | 26 | | 12 | 479 001 600 | 27 | | 13 | 6 227 020 800 | 28 | | 14 | 87 178 291 200 | 29 | | 15 | 1 307 674 368 000 | 30 | 31 | ## Посилання 32 | 33 | [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D1%96%D0%B0%D0%BB) 34 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 阶乘 2 | 3 | 在数学上, 一个正整数 `n` 的阶乘 (写作 `n!`), 就是所有小于等于 `n` 的正整数的乘积. 比如: 4 | 5 | ``` 6 | 5! = 5 * 4 * 3 * 2 * 1 = 120 7 | ``` 8 | 9 | | n | n! | 10 | | ----- | --------------------------: | 11 | | 0 | 1 | 12 | | 1 | 1 | 13 | | 2 | 2 | 14 | | 3 | 6 | 15 | | 4 | 24 | 16 | | 5 | 120 | 17 | | 6 | 720 | 18 | | 7 | 5 040 | 19 | | 8 | 40 320 | 20 | | 9 | 362 880 | 21 | | 10 | 3 628 800 | 22 | | 11 | 39 916 800 | 23 | | 12 | 479 001 600 | 24 | | 13 | 6 227 020 800 | 25 | | 14 | 87 178 291 200 | 26 | | 15 | 1 307 674 368 000 | 27 | 28 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/__test__/factorial.test.js: -------------------------------------------------------------------------------- 1 | import factorial from '../factorial'; 2 | 3 | describe('factorial', () => { 4 | it('should calculate factorial', () => { 5 | expect(factorial(0)).toBe(1); 6 | expect(factorial(1)).toBe(1); 7 | expect(factorial(5)).toBe(120); 8 | expect(factorial(8)).toBe(40320); 9 | expect(factorial(10)).toBe(3628800); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/__test__/factorialRecursive.test.js: -------------------------------------------------------------------------------- 1 | import factorialRecursive from '../factorialRecursive'; 2 | 3 | describe('factorialRecursive', () => { 4 | it('should calculate factorial', () => { 5 | expect(factorialRecursive(0)).toBe(1); 6 | expect(factorialRecursive(1)).toBe(1); 7 | expect(factorialRecursive(5)).toBe(120); 8 | expect(factorialRecursive(8)).toBe(40320); 9 | expect(factorialRecursive(10)).toBe(3628800); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/factorial.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {number} 4 | */ 5 | export default function factorial(number) { 6 | let result = 1; 7 | 8 | for (let i = 2; i <= number; i += 1) { 9 | result *= i; 10 | } 11 | 12 | return result; 13 | } 14 | -------------------------------------------------------------------------------- /src/algorithms/math/factorial/factorialRecursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {number} 4 | */ 5 | export default function factorialRecursive(number) { 6 | return number > 1 ? number * factorialRecursive(number - 1) : 1; 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/fast-powering/__test__/fastPowering.test.js: -------------------------------------------------------------------------------- 1 | import fastPowering from '../fastPowering'; 2 | 3 | describe('fastPowering', () => { 4 | it('should compute power in log(n) time', () => { 5 | expect(fastPowering(1, 1)).toBe(1); 6 | expect(fastPowering(2, 0)).toBe(1); 7 | expect(fastPowering(2, 2)).toBe(4); 8 | expect(fastPowering(2, 3)).toBe(8); 9 | expect(fastPowering(2, 4)).toBe(16); 10 | expect(fastPowering(2, 5)).toBe(32); 11 | expect(fastPowering(2, 6)).toBe(64); 12 | expect(fastPowering(2, 7)).toBe(128); 13 | expect(fastPowering(2, 8)).toBe(256); 14 | expect(fastPowering(3, 4)).toBe(81); 15 | expect(fastPowering(190, 2)).toBe(36100); 16 | expect(fastPowering(11, 5)).toBe(161051); 17 | expect(fastPowering(13, 11)).toBe(1792160394037); 18 | expect(fastPowering(9, 16)).toBe(1853020188851841); 19 | expect(fastPowering(16, 16)).toBe(18446744073709552000); 20 | expect(fastPowering(7, 21)).toBe(558545864083284000); 21 | expect(fastPowering(100, 9)).toBe(1000000000000000000); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/fast-powering/fastPowering.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Fast Powering Algorithm. 3 | * Recursive implementation to compute power. 4 | * 5 | * Complexity: log(n) 6 | * 7 | * @param {number} base - Number that will be raised to the power. 8 | * @param {number} power - The power that number will be raised to. 9 | * @return {number} 10 | */ 11 | export default function fastPowering(base, power) { 12 | if (power === 0) { 13 | // Anything that is raised to the power of zero is 1. 14 | return 1; 15 | } 16 | 17 | if (power % 2 === 0) { 18 | // If the power is even... 19 | // we may recursively redefine the result via twice smaller powers: 20 | // x^8 = x^4 * x^4. 21 | const multiplier = fastPowering(base, power / 2); 22 | return multiplier * multiplier; 23 | } 24 | 25 | // If the power is odd... 26 | // we may recursively redefine the result via twice smaller powers: 27 | // x^9 = x^4 * x^4 * x. 28 | const multiplier = fastPowering(base, Math.floor(power / 2)); 29 | return multiplier * multiplier * base; 30 | } 31 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/README.fr-FR.md: -------------------------------------------------------------------------------- 1 | # Nombre de Fibonacci 2 | 3 | _Read this in other languages:_ 4 | [english](README.md), 5 | [ქართული](README.ka-GE.md). 6 | 7 | En mathématiques, la suite de Fibonacci est une suite d'entiers 8 | dans laquelle chaque terme (après les deux premiers) 9 | est la somme des deux termes qui le précèdent. 10 | Les termes de cette suite sont appelés nombres de Fibonacci: 11 | 12 | `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...` 13 | 14 | Les carrés de Fibonacci en spirale s'ajustent ensemble pour former une spirale d'or. 15 | 16 | ![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png) 17 | 18 | La spirale de Fibonacci: approximation d'une spirale d'or créée en dessinant des arcs de cercle reliant les coins opposés de carrés dans un pavage Fibonacci[4] . Celui-ci utilise des carrés de tailles 1, 1, 2, 3, 5, 8, 13, 21, et 34. 19 | 20 | ![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg) 21 | 22 | ## References 23 | 24 | - [Wikipedia](https://fr.wikipedia.org/wiki/Suite_de_Fibonacci) 25 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/README.ka-GE.md: -------------------------------------------------------------------------------- 1 | # ფიბონაჩის რიცხვი 2 | 3 | მათემატიკაში ფიბონაჩის მიმდევრობა წარმოადგენს მთელ რიცხვთა მიმდევრობას, 4 | რომელშიც ყოველი რიცხვი (პირველი ორი რიცხვის შემდეგ) 5 | მისი წინამორბედი ორი რიცხვის 6 | ჯამის ტოლია: 7 | 8 | `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...` 9 | 10 | კვადრატების წყობა, სადაც ყოველი კვადრატის გვერდების სიგრძე, თანმიმდევრობით, ფიბონაჩის რიცხვებს შეესაბამება 11 | 12 | ![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png) 13 | 14 | ფიბონაჩის სპირალი: ოქროს სპირალის აპროქსიმაცია, რომელიც შექმნილია კვადრატების მოპირდაპირე კუთხეებს შორის შემაერთებელი რკალების გავლებით;[4] ამ შემთხვევაში, გამოყენებულ კვადრატთა [გვერდების] ზომებია: 1, 1, 2, 3, 5, 8, 13 და 21. 15 | 16 | ![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg) 17 | 18 | ## სქოლიო 19 | 20 | - [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) 21 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/README.md: -------------------------------------------------------------------------------- 1 | # Fibonacci Number 2 | 3 | _Read this in other languages:_ 4 | [français](README.fr-FR.md), 5 | [简体中文](README.zh-CN.md), 6 | [ქართული](README.ka-GE.md). 7 | 8 | In mathematics, the Fibonacci numbers are the numbers in the following 9 | integer sequence, called the Fibonacci sequence, and characterized by 10 | the fact that every number after the first two is the sum of the two 11 | preceding ones: 12 | 13 | `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...` 14 | 15 | A tiling with squares whose side lengths are successive Fibonacci numbers 16 | 17 | ![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png) 18 | 19 | The Fibonacci spiral: an approximation of the golden spiral created by drawing circular arcs connecting the opposite corners of squares in the Fibonacci tiling;[4] this one uses squares of sizes 1, 1, 2, 3, 5, 8, 13 and 21. 20 | 21 | ![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg) 22 | 23 | ## References 24 | 25 | - [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) 26 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 斐波那契数 2 | 3 | _Read this in other languages:_ 4 | [français](README.fr-FR.md), 5 | [english](README.md), 6 | [ქართული](README.ka-GE.md). 7 | 8 | 在数学中,斐波那契数是以下整数序列(称为斐波那契数列)中的数字,其特征在于前两个数字之后的每个数字都是前两个数字的和: 9 | 10 | `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...` 11 | 12 | 边长为连续斐波纳契数的正方形平铺 13 | 14 | ![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png) 15 | 16 | 17 | 斐波那契螺旋:通过绘制连接斐波那契平铺中正方形的相对角的圆弧而创建的金色螺旋的近似值; [4]该三角形使用大小为1、1、2、3、5、8、13和21的正方形。 18 | 19 | ![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg) 20 | 21 | ## References 22 | 23 | - [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) 24 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/__test__/fibonacci.test.js: -------------------------------------------------------------------------------- 1 | import fibonacci from '../fibonacci'; 2 | 3 | describe('fibonacci', () => { 4 | it('should calculate fibonacci correctly', () => { 5 | expect(fibonacci(1)).toEqual([1]); 6 | expect(fibonacci(2)).toEqual([1, 1]); 7 | expect(fibonacci(3)).toEqual([1, 1, 2]); 8 | expect(fibonacci(4)).toEqual([1, 1, 2, 3]); 9 | expect(fibonacci(5)).toEqual([1, 1, 2, 3, 5]); 10 | expect(fibonacci(6)).toEqual([1, 1, 2, 3, 5, 8]); 11 | expect(fibonacci(7)).toEqual([1, 1, 2, 3, 5, 8, 13]); 12 | expect(fibonacci(8)).toEqual([1, 1, 2, 3, 5, 8, 13, 21]); 13 | expect(fibonacci(9)).toEqual([1, 1, 2, 3, 5, 8, 13, 21, 34]); 14 | expect(fibonacci(10)).toEqual([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js: -------------------------------------------------------------------------------- 1 | import fibonacciNth from '../fibonacciNth'; 2 | 3 | describe('fibonacciNth', () => { 4 | it('should calculate fibonacci correctly', () => { 5 | expect(fibonacciNth(1)).toBe(1); 6 | expect(fibonacciNth(2)).toBe(1); 7 | expect(fibonacciNth(3)).toBe(2); 8 | expect(fibonacciNth(4)).toBe(3); 9 | expect(fibonacciNth(5)).toBe(5); 10 | expect(fibonacciNth(6)).toBe(8); 11 | expect(fibonacciNth(7)).toBe(13); 12 | expect(fibonacciNth(8)).toBe(21); 13 | expect(fibonacciNth(20)).toBe(6765); 14 | expect(fibonacciNth(30)).toBe(832040); 15 | expect(fibonacciNth(50)).toBe(12586269025); 16 | expect(fibonacciNth(70)).toBe(190392490709135); 17 | expect(fibonacciNth(71)).toBe(308061521170129); 18 | expect(fibonacciNth(72)).toBe(498454011879264); 19 | expect(fibonacciNth(73)).toBe(806515533049393); 20 | expect(fibonacciNth(74)).toBe(1304969544928657); 21 | expect(fibonacciNth(75)).toBe(2111485077978050); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/__test__/fibonacciNthClosedForm.test.js: -------------------------------------------------------------------------------- 1 | import fibonacciNthClosedForm from '../fibonacciNthClosedForm'; 2 | 3 | describe('fibonacciClosedForm', () => { 4 | it('should throw an error when trying to calculate fibonacci for not allowed positions', () => { 5 | const calculateFibonacciForNotAllowedPosition = () => { 6 | fibonacciNthClosedForm(76); 7 | }; 8 | 9 | expect(calculateFibonacciForNotAllowedPosition).toThrow(); 10 | }); 11 | 12 | it('should calculate fibonacci correctly', () => { 13 | expect(fibonacciNthClosedForm(1)).toBe(1); 14 | expect(fibonacciNthClosedForm(2)).toBe(1); 15 | expect(fibonacciNthClosedForm(3)).toBe(2); 16 | expect(fibonacciNthClosedForm(4)).toBe(3); 17 | expect(fibonacciNthClosedForm(5)).toBe(5); 18 | expect(fibonacciNthClosedForm(6)).toBe(8); 19 | expect(fibonacciNthClosedForm(7)).toBe(13); 20 | expect(fibonacciNthClosedForm(8)).toBe(21); 21 | expect(fibonacciNthClosedForm(20)).toBe(6765); 22 | expect(fibonacciNthClosedForm(30)).toBe(832040); 23 | expect(fibonacciNthClosedForm(50)).toBe(12586269025); 24 | expect(fibonacciNthClosedForm(70)).toBe(190392490709135); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/fibonacci.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Return a fibonacci sequence as an array. 3 | * 4 | * @param n 5 | * @return {number[]} 6 | */ 7 | export default function fibonacci(n) { 8 | const fibSequence = [1]; 9 | 10 | let currentValue = 1; 11 | let previousValue = 0; 12 | 13 | if (n === 1) { 14 | return fibSequence; 15 | } 16 | 17 | let iterationsCounter = n - 1; 18 | 19 | while (iterationsCounter) { 20 | currentValue += previousValue; 21 | previousValue = currentValue - previousValue; 22 | 23 | fibSequence.push(currentValue); 24 | 25 | iterationsCounter -= 1; 26 | } 27 | 28 | return fibSequence; 29 | } 30 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/fibonacciNth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Calculate fibonacci number at specific position using Dynamic Programming approach. 3 | * 4 | * @param n 5 | * @return {number} 6 | */ 7 | export default function fibonacciNth(n) { 8 | let currentValue = 1; 9 | let previousValue = 0; 10 | 11 | if (n === 1) { 12 | return 1; 13 | } 14 | 15 | let iterationsCounter = n - 1; 16 | 17 | while (iterationsCounter) { 18 | currentValue += previousValue; 19 | previousValue = currentValue - previousValue; 20 | 21 | iterationsCounter -= 1; 22 | } 23 | 24 | return currentValue; 25 | } 26 | -------------------------------------------------------------------------------- /src/algorithms/math/fibonacci/fibonacciNthClosedForm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Calculate fibonacci number at specific position using closed form function (Binet's formula). 3 | * @see: https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression 4 | * 5 | * @param {number} position - Position number of fibonacci sequence (must be number from 1 to 75). 6 | * @return {number} 7 | */ 8 | export default function fibonacciClosedForm(position) { 9 | const topMaxValidPosition = 70; 10 | 11 | // Check that position is valid. 12 | if (position < 1 || position > topMaxValidPosition) { 13 | throw new Error(`Can't handle position smaller than 1 or greater than ${topMaxValidPosition}`); 14 | } 15 | 16 | // Calculate √5 to re-use it in further formulas. 17 | const sqrt5 = Math.sqrt(5); 18 | // Calculate φ constant (≈ 1.61803). 19 | const phi = (1 + sqrt5) / 2; 20 | 21 | // Calculate fibonacci number using Binet's formula. 22 | return Math.floor((phi ** position) / sqrt5 + 0.5); 23 | } 24 | -------------------------------------------------------------------------------- /src/algorithms/math/fourier-transform/__test__/discreteFourierTransform.test.js: -------------------------------------------------------------------------------- 1 | import discreteFourierTransform from '../discreteFourierTransform'; 2 | import FourierTester from './FourierTester'; 3 | 4 | describe('discreteFourierTransform', () => { 5 | it('should split signal into frequencies', () => { 6 | FourierTester.testDirectFourierTransform(discreteFourierTransform); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/algorithms/math/fourier-transform/__test__/inverseDiscreteFourierTransform.test.js: -------------------------------------------------------------------------------- 1 | import inverseDiscreteFourierTransform from '../inverseDiscreteFourierTransform'; 2 | import FourierTester from './FourierTester'; 3 | 4 | describe('inverseDiscreteFourierTransform', () => { 5 | it('should calculate output signal out of input frequencies', () => { 6 | FourierTester.testInverseFourierTransform(inverseDiscreteFourierTransform); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/algorithms/math/horner-method/__test__/classicPolynome.test.js: -------------------------------------------------------------------------------- 1 | import classicPolynome from '../classicPolynome'; 2 | 3 | describe('classicPolynome', () => { 4 | it('should evaluate the polynomial for the specified value of x correctly', () => { 5 | expect(classicPolynome([8], 0.1)).toBe(8); 6 | expect(classicPolynome([2, 4, 2, 5], 0.555)).toBe(7.68400775); 7 | expect(classicPolynome([2, 4, 2, 5], 0.75)).toBe(9.59375); 8 | expect(classicPolynome([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125); 9 | expect(classicPolynome([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.1367300651406251); 10 | expect(classicPolynome([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001); 11 | expect(classicPolynome([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001); 12 | expect(classicPolynome([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/math/horner-method/__test__/hornerMethod.test.js: -------------------------------------------------------------------------------- 1 | import hornerMethod from '../hornerMethod'; 2 | import classicPolynome from '../classicPolynome'; 3 | 4 | describe('hornerMethod', () => { 5 | it('should evaluate the polynomial for the specified value of x correctly', () => { 6 | expect(hornerMethod([8], 0.1)).toBe(8); 7 | expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(7.68400775); 8 | expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(9.59375); 9 | expect(hornerMethod([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125); 10 | expect(hornerMethod([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.136730065140625); 11 | expect(hornerMethod([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001); 12 | expect(hornerMethod([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001); 13 | expect(hornerMethod([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034); 14 | }); 15 | 16 | it('should evaluate the same polynomial value as classical approach', () => { 17 | expect(hornerMethod([8], 0.1)).toBe(classicPolynome([8], 0.1)); 18 | expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(classicPolynome([2, 4, 2, 5], 0.555)); 19 | expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(classicPolynome([2, 4, 2, 5], 0.75)); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/math/horner-method/classicPolynome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the evaluation of a polynomial function at a certain point. 3 | * Uses straightforward approach with powers. 4 | * 5 | * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2) 6 | * @param {number} xVal 7 | * @return {number} 8 | */ 9 | export default function classicPolynome(coefficients, xVal) { 10 | return coefficients.reverse().reduce( 11 | (accumulator, currentCoefficient, index) => { 12 | return accumulator + currentCoefficient * (xVal ** index); 13 | }, 14 | 0, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/algorithms/math/horner-method/hornerMethod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the evaluation of a polynomial function at a certain point. 3 | * Uses Horner's rule. 4 | * 5 | * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2) 6 | * @param {number} xVal 7 | * @return {number} 8 | */ 9 | export default function hornerMethod(coefficients, xVal) { 10 | return coefficients.reduce( 11 | (accumulator, currentCoefficient) => { 12 | return accumulator * xVal + currentCoefficient; 13 | }, 14 | 0, 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/algorithms/math/integer-partition/README.md: -------------------------------------------------------------------------------- 1 | # Integer Partition 2 | 3 | In number theory and combinatorics, a partition of a positive 4 | integer `n`, also called an **integer partition**, is a way of 5 | writing `n` as a sum of positive integers. 6 | 7 | Two sums that differ only in the order of their summands are 8 | considered the same partition. For example, `4` can be partitioned 9 | in five distinct ways: 10 | 11 | ``` 12 | 4 13 | 3 + 1 14 | 2 + 2 15 | 2 + 1 + 1 16 | 1 + 1 + 1 + 1 17 | ``` 18 | 19 | The order-dependent composition `1 + 3` is the same partition 20 | as `3 + 1`, while the two distinct 21 | compositions `1 + 2 + 1` and `1 + 1 + 2` represent the same 22 | partition `2 + 1 + 1`. 23 | 24 | Young diagrams associated to the partitions of the positive 25 | integers `1` through `8`. They are arranged so that images 26 | under the reflection about the main diagonal of the square 27 | are conjugate partitions. 28 | 29 | ![Integer Partition](https://upload.wikimedia.org/wikipedia/commons/d/d8/Ferrer_partitioning_diagrams.svg) 30 | 31 | ## References 32 | 33 | - [Wikipedia](https://en.wikipedia.org/wiki/Partition_(number_theory)) 34 | - [YouTube](https://www.youtube.com/watch?v=ZaVM057DuzE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 35 | -------------------------------------------------------------------------------- /src/algorithms/math/integer-partition/__test__/integerPartition.test.js: -------------------------------------------------------------------------------- 1 | import integerPartition from '../integerPartition'; 2 | 3 | describe('integerPartition', () => { 4 | it('should partition the number', () => { 5 | expect(integerPartition(1)).toBe(1); 6 | expect(integerPartition(2)).toBe(2); 7 | expect(integerPartition(3)).toBe(3); 8 | expect(integerPartition(4)).toBe(5); 9 | expect(integerPartition(5)).toBe(7); 10 | expect(integerPartition(6)).toBe(11); 11 | expect(integerPartition(7)).toBe(15); 12 | expect(integerPartition(8)).toBe(22); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/math/is-power-of-two/__test__/isPowerOfTwo.test.js: -------------------------------------------------------------------------------- 1 | import isPowerOfTwo from '../isPowerOfTwo'; 2 | 3 | describe('isPowerOfTwo', () => { 4 | it('should check if the number is made by multiplying twos', () => { 5 | expect(isPowerOfTwo(-1)).toBe(false); 6 | expect(isPowerOfTwo(0)).toBe(false); 7 | expect(isPowerOfTwo(1)).toBe(true); 8 | expect(isPowerOfTwo(2)).toBe(true); 9 | expect(isPowerOfTwo(3)).toBe(false); 10 | expect(isPowerOfTwo(4)).toBe(true); 11 | expect(isPowerOfTwo(5)).toBe(false); 12 | expect(isPowerOfTwo(6)).toBe(false); 13 | expect(isPowerOfTwo(7)).toBe(false); 14 | expect(isPowerOfTwo(8)).toBe(true); 15 | expect(isPowerOfTwo(10)).toBe(false); 16 | expect(isPowerOfTwo(12)).toBe(false); 17 | expect(isPowerOfTwo(16)).toBe(true); 18 | expect(isPowerOfTwo(31)).toBe(false); 19 | expect(isPowerOfTwo(64)).toBe(true); 20 | expect(isPowerOfTwo(1024)).toBe(true); 21 | expect(isPowerOfTwo(1023)).toBe(false); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/is-power-of-two/__test__/isPowerOfTwoBitwise.test.js: -------------------------------------------------------------------------------- 1 | import isPowerOfTwoBitwise from '../isPowerOfTwoBitwise'; 2 | 3 | describe('isPowerOfTwoBitwise', () => { 4 | it('should check if the number is made by multiplying twos', () => { 5 | expect(isPowerOfTwoBitwise(-1)).toBe(false); 6 | expect(isPowerOfTwoBitwise(0)).toBe(false); 7 | expect(isPowerOfTwoBitwise(1)).toBe(true); 8 | expect(isPowerOfTwoBitwise(2)).toBe(true); 9 | expect(isPowerOfTwoBitwise(3)).toBe(false); 10 | expect(isPowerOfTwoBitwise(4)).toBe(true); 11 | expect(isPowerOfTwoBitwise(5)).toBe(false); 12 | expect(isPowerOfTwoBitwise(6)).toBe(false); 13 | expect(isPowerOfTwoBitwise(7)).toBe(false); 14 | expect(isPowerOfTwoBitwise(8)).toBe(true); 15 | expect(isPowerOfTwoBitwise(10)).toBe(false); 16 | expect(isPowerOfTwoBitwise(12)).toBe(false); 17 | expect(isPowerOfTwoBitwise(16)).toBe(true); 18 | expect(isPowerOfTwoBitwise(31)).toBe(false); 19 | expect(isPowerOfTwoBitwise(64)).toBe(true); 20 | expect(isPowerOfTwoBitwise(1024)).toBe(true); 21 | expect(isPowerOfTwoBitwise(1023)).toBe(false); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/math/is-power-of-two/isPowerOfTwo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {boolean} 4 | */ 5 | export default function isPowerOfTwo(number) { 6 | // 1 (2^0) is the smallest power of two. 7 | if (number < 1) { 8 | return false; 9 | } 10 | 11 | // Let's find out if we can divide the number by two 12 | // many times without remainder. 13 | let dividedNumber = number; 14 | while (dividedNumber !== 1) { 15 | if (dividedNumber % 2 !== 0) { 16 | // For every case when remainder isn't zero we can say that this number 17 | // couldn't be a result of power of two. 18 | return false; 19 | } 20 | 21 | dividedNumber /= 2; 22 | } 23 | 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /src/algorithms/math/is-power-of-two/isPowerOfTwoBitwise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {boolean} 4 | */ 5 | export default function isPowerOfTwoBitwise(number) { 6 | // 1 (2^0) is the smallest power of two. 7 | if (number < 1) { 8 | return false; 9 | } 10 | 11 | /* 12 | * Powers of two in binary look like this: 13 | * 1: 0001 14 | * 2: 0010 15 | * 4: 0100 16 | * 8: 1000 17 | * 18 | * Note that there is always exactly 1 bit set. The only exception is with a signed integer. 19 | * e.g. An 8-bit signed integer with a value of -128 looks like: 20 | * 10000000 21 | * 22 | * So after checking that the number is greater than zero, we can use a clever little bit 23 | * hack to test that one and only one bit is set. 24 | */ 25 | return (number & (number - 1)) === 0; 26 | } 27 | -------------------------------------------------------------------------------- /src/algorithms/math/least-common-multiple/__test__/leastCommonMultiple.test.js: -------------------------------------------------------------------------------- 1 | import leastCommonMultiple from '../leastCommonMultiple'; 2 | 3 | describe('leastCommonMultiple', () => { 4 | it('should find least common multiple', () => { 5 | expect(leastCommonMultiple(0, 0)).toBe(0); 6 | expect(leastCommonMultiple(1, 0)).toBe(0); 7 | expect(leastCommonMultiple(0, 1)).toBe(0); 8 | expect(leastCommonMultiple(4, 6)).toBe(12); 9 | expect(leastCommonMultiple(6, 21)).toBe(42); 10 | expect(leastCommonMultiple(7, 2)).toBe(14); 11 | expect(leastCommonMultiple(3, 5)).toBe(15); 12 | expect(leastCommonMultiple(7, 3)).toBe(21); 13 | expect(leastCommonMultiple(1000000, 2)).toBe(1000000); 14 | expect(leastCommonMultiple(-9, -18)).toBe(18); 15 | expect(leastCommonMultiple(-7, -9)).toBe(63); 16 | expect(leastCommonMultiple(-7, 9)).toBe(63); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/math/least-common-multiple/leastCommonMultiple.js: -------------------------------------------------------------------------------- 1 | import euclideanAlgorithm from '../euclidean-algorithm/euclideanAlgorithm'; 2 | 3 | /** 4 | * @param {number} a 5 | * @param {number} b 6 | * @return {number} 7 | */ 8 | 9 | export default function leastCommonMultiple(a, b) { 10 | return ((a === 0) || (b === 0)) ? 0 : Math.abs(a * b) / euclideanAlgorithm(a, b); 11 | } 12 | -------------------------------------------------------------------------------- /src/algorithms/math/liu-hui/__test__/liuHui.test.js: -------------------------------------------------------------------------------- 1 | import liuHui from '../liuHui'; 2 | 3 | describe('liuHui', () => { 4 | it('should calculate π based on 12-gon', () => { 5 | expect(liuHui(1)).toBe(3); 6 | }); 7 | 8 | it('should calculate π based on 24-gon', () => { 9 | expect(liuHui(2)).toBe(3.105828541230249); 10 | }); 11 | 12 | it('should calculate π based on 6144-gon', () => { 13 | expect(liuHui(10)).toBe(3.1415921059992717); 14 | }); 15 | 16 | it('should calculate π based on 201326592-gon', () => { 17 | expect(liuHui(25)).toBe(3.141592653589793); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/math/pascal-triangle/__test__/pascalTriangle.test.js: -------------------------------------------------------------------------------- 1 | import pascalTriangle from '../pascalTriangle'; 2 | 3 | describe('pascalTriangle', () => { 4 | it('should calculate Pascal Triangle coefficients for specific line number', () => { 5 | expect(pascalTriangle(0)).toEqual([1]); 6 | expect(pascalTriangle(1)).toEqual([1, 1]); 7 | expect(pascalTriangle(2)).toEqual([1, 2, 1]); 8 | expect(pascalTriangle(3)).toEqual([1, 3, 3, 1]); 9 | expect(pascalTriangle(4)).toEqual([1, 4, 6, 4, 1]); 10 | expect(pascalTriangle(5)).toEqual([1, 5, 10, 10, 5, 1]); 11 | expect(pascalTriangle(6)).toEqual([1, 6, 15, 20, 15, 6, 1]); 12 | expect(pascalTriangle(7)).toEqual([1, 7, 21, 35, 35, 21, 7, 1]); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/math/pascal-triangle/__test__/pascalTriangleRecursive.test.js: -------------------------------------------------------------------------------- 1 | import pascalTriangleRecursive from '../pascalTriangleRecursive'; 2 | 3 | describe('pascalTriangleRecursive', () => { 4 | it('should calculate Pascal Triangle coefficients for specific line number', () => { 5 | expect(pascalTriangleRecursive(0)).toEqual([1]); 6 | expect(pascalTriangleRecursive(1)).toEqual([1, 1]); 7 | expect(pascalTriangleRecursive(2)).toEqual([1, 2, 1]); 8 | expect(pascalTriangleRecursive(3)).toEqual([1, 3, 3, 1]); 9 | expect(pascalTriangleRecursive(4)).toEqual([1, 4, 6, 4, 1]); 10 | expect(pascalTriangleRecursive(5)).toEqual([1, 5, 10, 10, 5, 1]); 11 | expect(pascalTriangleRecursive(6)).toEqual([1, 6, 15, 20, 15, 6, 1]); 12 | expect(pascalTriangleRecursive(7)).toEqual([1, 7, 21, 35, 35, 21, 7, 1]); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/math/pascal-triangle/pascalTriangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} lineNumber - zero based. 3 | * @return {number[]} 4 | */ 5 | export default function pascalTriangle(lineNumber) { 6 | const currentLine = [1]; 7 | 8 | const currentLineSize = lineNumber + 1; 9 | 10 | for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) { 11 | // See explanation of this formula in README. 12 | currentLine[numIndex] = (currentLine[numIndex - 1] * (lineNumber - numIndex + 1)) / numIndex; 13 | } 14 | 15 | return currentLine; 16 | } 17 | -------------------------------------------------------------------------------- /src/algorithms/math/pascal-triangle/pascalTriangleRecursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} lineNumber - zero based. 3 | * @return {number[]} 4 | */ 5 | export default function pascalTriangleRecursive(lineNumber) { 6 | if (lineNumber === 0) { 7 | return [1]; 8 | } 9 | 10 | const currentLineSize = lineNumber + 1; 11 | const previousLineSize = currentLineSize - 1; 12 | 13 | // Create container for current line values. 14 | const currentLine = []; 15 | 16 | // We'll calculate current line based on previous one. 17 | const previousLine = pascalTriangleRecursive(lineNumber - 1); 18 | 19 | // Let's go through all elements of current line except the first and 20 | // last one (since they were and will be filled with 1's) and calculate 21 | // current coefficient based on previous line. 22 | for (let numIndex = 0; numIndex < currentLineSize; numIndex += 1) { 23 | const leftCoefficient = (numIndex - 1) >= 0 ? previousLine[numIndex - 1] : 0; 24 | const rightCoefficient = numIndex < previousLineSize ? previousLine[numIndex] : 0; 25 | 26 | currentLine[numIndex] = leftCoefficient + rightCoefficient; 27 | } 28 | 29 | return currentLine; 30 | } 31 | -------------------------------------------------------------------------------- /src/algorithms/math/primality-test/trialDivision.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} number 3 | * @return {boolean} 4 | */ 5 | export default function trialDivision(number) { 6 | // Check if number is integer. 7 | if (number % 1 !== 0) { 8 | return false; 9 | } 10 | 11 | if (number <= 1) { 12 | // If number is less than one then it isn't prime by definition. 13 | return false; 14 | } 15 | 16 | if (number <= 3) { 17 | // All numbers from 2 to 3 are prime. 18 | return true; 19 | } 20 | 21 | // If the number is not divided by 2 then we may eliminate all further even dividers. 22 | if (number % 2 === 0) { 23 | return false; 24 | } 25 | 26 | // If there is no dividers up to square root of n then there is no higher dividers as well. 27 | const dividerLimit = Math.sqrt(number); 28 | for (let divider = 3; divider <= dividerLimit; divider += 2) { 29 | if (number % divider === 0) { 30 | return false; 31 | } 32 | } 33 | 34 | return true; 35 | } 36 | -------------------------------------------------------------------------------- /src/algorithms/math/radian/README.md: -------------------------------------------------------------------------------- 1 | # Radian 2 | 3 | The **radian** (symbol **rad**) is the unit for measuring angles, and is the 4 | standard unit of angular measure used in many areas of mathematics. 5 | 6 | The length of an arc of a unit circle is numerically equal to the measurement 7 | in radians of the angle that it subtends; one radian is just under `57.3` degrees. 8 | 9 | An arc of a circle with the same length as the radius of that circle subtends an 10 | angle of `1 radian`. The circumference subtends an angle of `2π radians`. 11 | 12 | ![Radian](https://upload.wikimedia.org/wikipedia/commons/4/4e/Circle_radians.gif) 13 | 14 | A complete revolution is 2π radians (shown here with a circle of radius one and 15 | thus circumference `2π`). 16 | 17 | ![2 pi Radian](https://upload.wikimedia.org/wikipedia/commons/6/67/2pi-unrolled.gif) 18 | 19 | **Conversions** 20 | 21 | | Radians | Degrees | 22 | | :-----: | :-----: | 23 | | 0 | 0° | 24 | | π/12 | 15° | 25 | | π/6 | 30° | 26 | | π/4 | 45° | 27 | | 1 | 57.3° | 28 | | π/3 | 60° | 29 | | π/2 | 90° | 30 | | π | 180° | 31 | | 2π | 360° | 32 | 33 | 34 | ## References 35 | 36 | - [Wikipedia](https://en.wikipedia.org/wiki/Radian) 37 | -------------------------------------------------------------------------------- /src/algorithms/math/radian/__test__/degreeToRadian.test.js: -------------------------------------------------------------------------------- 1 | import degreeToRadian from '../degreeToRadian'; 2 | 3 | describe('degreeToRadian', () => { 4 | it('should convert degree to radian', () => { 5 | expect(degreeToRadian(0)).toBe(0); 6 | expect(degreeToRadian(45)).toBe(Math.PI / 4); 7 | expect(degreeToRadian(90)).toBe(Math.PI / 2); 8 | expect(degreeToRadian(180)).toBe(Math.PI); 9 | expect(degreeToRadian(270)).toBe((3 * Math.PI) / 2); 10 | expect(degreeToRadian(360)).toBe(2 * Math.PI); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/math/radian/__test__/radianToDegree.test.js: -------------------------------------------------------------------------------- 1 | import radianToDegree from '../radianToDegree'; 2 | 3 | describe('radianToDegree', () => { 4 | it('should convert radian to degree', () => { 5 | expect(radianToDegree(0)).toBe(0); 6 | expect(radianToDegree(Math.PI / 4)).toBe(45); 7 | expect(radianToDegree(Math.PI / 2)).toBe(90); 8 | expect(radianToDegree(Math.PI)).toBe(180); 9 | expect(radianToDegree((3 * Math.PI) / 2)).toBe(270); 10 | expect(radianToDegree(2 * Math.PI)).toBe(360); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/math/radian/degreeToRadian.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} degree 3 | * @return {number} 4 | */ 5 | export default function degreeToRadian(degree) { 6 | return degree * (Math.PI / 180); 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/radian/radianToDegree.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} radian 3 | * @return {number} 4 | */ 5 | export default function radianToDegree(radian) { 6 | return radian * (180 / Math.PI); 7 | } 8 | -------------------------------------------------------------------------------- /src/algorithms/math/sieve-of-eratosthenes/__test__/sieveOfEratosthenes.test.js: -------------------------------------------------------------------------------- 1 | import sieveOfEratosthenes from '../sieveOfEratosthenes'; 2 | 3 | describe('sieveOfEratosthenes', () => { 4 | it('should find all primes less than or equal to n', () => { 5 | expect(sieveOfEratosthenes(5)).toEqual([2, 3, 5]); 6 | expect(sieveOfEratosthenes(10)).toEqual([2, 3, 5, 7]); 7 | expect(sieveOfEratosthenes(100)).toEqual([ 8 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 9 | 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 10 | ]); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/math/sieve-of-eratosthenes/sieveOfEratosthenes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} maxNumber 3 | * @return {number[]} 4 | */ 5 | export default function sieveOfEratosthenes(maxNumber) { 6 | const isPrime = new Array(maxNumber + 1).fill(true); 7 | isPrime[0] = false; 8 | isPrime[1] = false; 9 | 10 | const primes = []; 11 | 12 | for (let number = 2; number <= maxNumber; number += 1) { 13 | if (isPrime[number] === true) { 14 | primes.push(number); 15 | 16 | /* 17 | * Optimisation. 18 | * Start marking multiples of `p` from `p * p`, and not from `2 * p`. 19 | * The reason why this works is because, at that point, smaller multiples 20 | * of `p` will have already been marked `false`. 21 | * 22 | * Warning: When working with really big numbers, the following line may cause overflow 23 | * In that case, it can be changed to: 24 | * let nextNumber = 2 * number; 25 | */ 26 | let nextNumber = number * number; 27 | 28 | while (nextNumber <= maxNumber) { 29 | isPrime[nextNumber] = false; 30 | nextNumber += number; 31 | } 32 | } 33 | } 34 | 35 | return primes; 36 | } 37 | -------------------------------------------------------------------------------- /src/algorithms/search/binary-search/README.es-ES.md: -------------------------------------------------------------------------------- 1 | # Búsqueda binaria 2 | 3 | _Lea esto en otros idiomas:_ 4 | [English](README.md) 5 | [Português brasileiro](README.pt-BR.md). 6 | 7 | En informática, la búsqueda binaria, también conocida como búsqueda de medio intervalo 8 | búsqueda, búsqueda logarítmica, o corte binario, es un algoritmo de búsqueda 9 | que encuentra la posición de un valor objetivo dentro de una matriz 10 | ordenada. La búsqueda binaria compara el valor objetivo con el elemento central 11 | de la matriz; si son desiguales, se elimina la mitad en la que 12 | la mitad en la que no puede estar el objetivo se elimina y la búsqueda continúa 13 | en la mitad restante hasta que tenga éxito. Si la búsqueda 14 | termina con la mitad restante vacía, el objetivo no está 15 | en la matriz. 16 | 17 | ![Búsqueda binaria](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg) 18 | 19 | ## Complejidad 20 | 21 | **Complejidad de tiempo**: `O(log(n))` - ya que dividimos el área de búsqueda en dos para cada 22 | siguiente iteración. 23 | 24 | ## Referencias 25 | 26 | - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm) 27 | - [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 28 | -------------------------------------------------------------------------------- /src/algorithms/search/binary-search/README.md: -------------------------------------------------------------------------------- 1 | # Binary Search 2 | 3 | _Read this in other languages:_ 4 | [Português brasileiro](README.pt-BR.md). 5 | [Español](README.es-ES.md). 6 | 7 | In computer science, binary search, also known as half-interval 8 | search, logarithmic search, or binary chop, is a search algorithm 9 | that finds the position of a target value within a sorted 10 | array. Binary search compares the target value to the middle 11 | element of the array; if they are unequal, the half in which 12 | the target cannot lie is eliminated and the search continues 13 | on the remaining half until it is successful. If the search 14 | ends with the remaining half being empty, the target is not 15 | in the array. 16 | 17 | ![Binary Search](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg) 18 | 19 | ## Complexity 20 | 21 | **Time Complexity**: `O(log(n))` - since we split search area by two for every 22 | next iteration. 23 | 24 | ## References 25 | 26 | - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm) 27 | - [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 28 | -------------------------------------------------------------------------------- /src/algorithms/search/binary-search/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Busca Binária 2 | 3 | _Leia isso em outras línguas:_ 4 | [english](README.md). 5 | [Español](README.es-ES.md). 6 | 7 | Em ciência da computação, busca binária, também conhecida como busca de meio-intervalo, busca logarítmica ou corte binário, é um algoritmo de pesquisa 8 | que encontra a posição de um elemento alvo dentro de um 9 | vetor ordenado. O algoritmo compara o elemento alvo com o elemento central do vetor; se eles são diferentes, a metade em que 10 | o elemento alvo não pode estar é eliminada e a busca continua 11 | na metade remanescente até que o elemento alvo seja encontrado. Se a busca 12 | terminar com a metade remanescente vazia, o elemento alvo não está presente no vetor. 13 | 14 | ![Busca Binária](https://upload.wikimedia.org/wikipedia/commons/8/83/Binary_Search_Depiction.svg) 15 | 16 | ## Complexidade 17 | 18 | **Complexidade de Tempo**: `O(log(n))` - pois a área de busca é dividida por dois a cada iteração. 19 | 20 | ## Referências 21 | 22 | - [Wikipedia](https://en.wikipedia.org/wiki/Binary_search_algorithm) 23 | - [YouTube](https://www.youtube.com/watch?v=P3YID7liBug&index=29&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 24 | -------------------------------------------------------------------------------- /src/algorithms/search/linear-search/README.md: -------------------------------------------------------------------------------- 1 | # Linear Search 2 | 3 | _Read this in other languages:_ 4 | [Português brasileiro](README.pt-BR.md). 5 | 6 | In computer science, linear search or sequential search is a 7 | method for finding a target value within a list. It sequentially 8 | checks each element of the list for the target value until a 9 | match is found or until all the elements have been searched. 10 | Linear search runs in at worst linear time and makes at most `n` 11 | comparisons, where `n` is the length of the list. 12 | 13 | ![Linear Search](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif) 14 | 15 | ## Complexity 16 | 17 | **Time Complexity**: `O(n)` - since in worst case we're checking each element 18 | exactly once. 19 | 20 | ## References 21 | - [Wikipedia](https://en.wikipedia.org/wiki/Linear_search) 22 | - [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm) 23 | - [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w) 24 | -------------------------------------------------------------------------------- /src/algorithms/search/linear-search/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Busca Linear 2 | 3 | _Leia isso em outras línguas:_ 4 | [english](README.md). 5 | 6 | Na Ciência da Computação, busca linear ou busca sequencial é um método para encontrar um elemento alvo em uma lista. 7 | O algoritmo verifica sequencialmente cada elemento da lista procurando o elemento alvo até ele ser encontrado ou até ter verificado todos os elementos. 8 | A Busca linear realiza no máximo `n` comparações, onde `n` é o tamanho da lista. 9 | 10 | ![Busca Linear](https://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif) 11 | 12 | ## Complexidade 13 | 14 | **Complexidade de Tempo**: `O(n)` - pois no pior caso devemos verificar cada elemento exatamente uma vez. 15 | 16 | ## Referências 17 | - [Wikipedia](https://en.wikipedia.org/wiki/Linear_search) 18 | - [TutorialsPoint](https://www.tutorialspoint.com/data_structures_algorithms/linear_search_algorithm.htm) 19 | - [Youtube](https://www.youtube.com/watch?v=SGU9duLE30w) 20 | -------------------------------------------------------------------------------- /src/algorithms/search/linear-search/linearSearch.js: -------------------------------------------------------------------------------- 1 | import Comparator from '../../../utils/comparator/Comparator'; 2 | 3 | /** 4 | * Linear search implementation. 5 | * 6 | * @param {*[]} array 7 | * @param {*} seekElement 8 | * @param {function(a, b)} [comparatorCallback] 9 | * @return {number[]} 10 | */ 11 | export default function linearSearch(array, seekElement, comparatorCallback) { 12 | const comparator = new Comparator(comparatorCallback); 13 | const foundIndices = []; 14 | 15 | array.forEach((element, index) => { 16 | if (comparator.equal(element, seekElement)) { 17 | foundIndices.push(index); 18 | } 19 | }); 20 | 21 | return foundIndices; 22 | } 23 | -------------------------------------------------------------------------------- /src/algorithms/sets/cartesian-product/README.md: -------------------------------------------------------------------------------- 1 | # Cartesian Product 2 | 3 | In set theory a Cartesian product is a mathematical operation that returns a set 4 | (or product set or simply product) from multiple sets. That is, for sets A and B, 5 | the Cartesian product A × B is the set of all ordered pairs (a, b) 6 | where a ∈ A and b ∈ B. 7 | 8 | Cartesian product `AxB` of two sets `A={x,y,z}` and `B={1,2,3}` 9 | 10 | ![Cartesian Product of Two Sets](https://upload.wikimedia.org/wikipedia/commons/4/4e/Cartesian_Product_qtl1.svg) 11 | 12 | ## References 13 | 14 | [Wikipedia](https://en.wikipedia.org/wiki/Cartesian_product) 15 | -------------------------------------------------------------------------------- /src/algorithms/sets/cartesian-product/__test__/cartesianProduct.test.js: -------------------------------------------------------------------------------- 1 | import cartesianProduct from '../cartesianProduct'; 2 | 3 | describe('cartesianProduct', () => { 4 | it('should return null if there is not enough info for calculation', () => { 5 | const product1 = cartesianProduct([1], null); 6 | const product2 = cartesianProduct([], null); 7 | 8 | expect(product1).toBeNull(); 9 | expect(product2).toBeNull(); 10 | }); 11 | 12 | it('should calculate the product of two sets', () => { 13 | const product1 = cartesianProduct([1], [1]); 14 | const product2 = cartesianProduct([1, 2], [3, 5]); 15 | 16 | expect(product1).toEqual([[1, 1]]); 17 | expect(product2).toEqual([[1, 3], [1, 5], [2, 3], [2, 5]]); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/sets/cartesian-product/cartesianProduct.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates Cartesian Product of two sets. 3 | * @param {*[]} setA 4 | * @param {*[]} setB 5 | * @return {*[]} 6 | */ 7 | export default function cartesianProduct(setA, setB) { 8 | // Check if input sets are not empty. 9 | // Otherwise return null since we can't generate Cartesian Product out of them. 10 | if (!setA || !setB || !setA.length || !setB.length) { 11 | return null; 12 | } 13 | 14 | // Init product set. 15 | const product = []; 16 | 17 | // Now, let's go through all elements of a first and second set and form all possible pairs. 18 | for (let indexA = 0; indexA < setA.length; indexA += 1) { 19 | for (let indexB = 0; indexB < setB.length; indexB += 1) { 20 | // Add current product pair to the product set. 21 | product.push([setA[indexA], setB[indexB]]); 22 | } 23 | } 24 | 25 | // Return cartesian product set. 26 | return product; 27 | } 28 | -------------------------------------------------------------------------------- /src/algorithms/sets/combination-sum/__test__/combinationSum.test.js: -------------------------------------------------------------------------------- 1 | import combinationSum from '../combinationSum'; 2 | 3 | describe('combinationSum', () => { 4 | it('should find all combinations with specific sum', () => { 5 | expect(combinationSum([1], 4)).toEqual([ 6 | [1, 1, 1, 1], 7 | ]); 8 | 9 | expect(combinationSum([2, 3, 6, 7], 7)).toEqual([ 10 | [2, 2, 3], 11 | [7], 12 | ]); 13 | 14 | expect(combinationSum([2, 3, 5], 8)).toEqual([ 15 | [2, 2, 2, 2], 16 | [2, 3, 3], 17 | [3, 5], 18 | ]); 19 | 20 | expect(combinationSum([2, 5], 3)).toEqual([]); 21 | 22 | expect(combinationSum([], 3)).toEqual([]); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/combineWithRepetitions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {*[]} comboOptions 3 | * @param {number} comboLength 4 | * @return {*[]} 5 | */ 6 | export default function combineWithRepetitions(comboOptions, comboLength) { 7 | // If the length of the combination is 1 then each element of the original array 8 | // is a combination itself. 9 | if (comboLength === 1) { 10 | return comboOptions.map((comboOption) => [comboOption]); 11 | } 12 | 13 | // Init combinations array. 14 | const combos = []; 15 | 16 | // Remember characters one by one and concatenate them to combinations of smaller lengths. 17 | // We don't extract elements here because the repetitions are allowed. 18 | comboOptions.forEach((currentOption, optionIndex) => { 19 | // Generate combinations of smaller size. 20 | const smallerCombos = combineWithRepetitions( 21 | comboOptions.slice(optionIndex), 22 | comboLength - 1, 23 | ); 24 | 25 | // Concatenate currentOption with all combinations of smaller size. 26 | smallerCombos.forEach((smallerCombo) => { 27 | combos.push([currentOption].concat(smallerCombo)); 28 | }); 29 | }); 30 | 31 | return combos; 32 | } 33 | -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/combineWithoutRepetitions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {*[]} comboOptions 3 | * @param {number} comboLength 4 | * @return {*[]} 5 | */ 6 | export default function combineWithoutRepetitions(comboOptions, comboLength) { 7 | // If the length of the combination is 1 then each element of the original array 8 | // is a combination itself. 9 | if (comboLength === 1) { 10 | return comboOptions.map((comboOption) => [comboOption]); 11 | } 12 | 13 | // Init combinations array. 14 | const combos = []; 15 | 16 | // Extract characters one by one and concatenate them to combinations of smaller lengths. 17 | // We need to extract them because we don't want to have repetitions after concatenation. 18 | comboOptions.forEach((currentOption, optionIndex) => { 19 | // Generate combinations of smaller size. 20 | const smallerCombos = combineWithoutRepetitions( 21 | comboOptions.slice(optionIndex + 1), 22 | comboLength - 1, 23 | ); 24 | 25 | // Concatenate currentOption with all combinations of smaller size. 26 | smallerCombos.forEach((smallerCombo) => { 27 | combos.push([currentOption].concat(smallerCombo)); 28 | }); 29 | }); 30 | 31 | return combos; 32 | } 33 | -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/images/combinations-overview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/combinations/images/combinations-overview.jpg -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/images/combinations-with-repetitions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/combinations/images/combinations-with-repetitions.jpg -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/images/combinations-without-repetitions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/combinations/images/combinations-without-repetitions.jpg -------------------------------------------------------------------------------- /src/algorithms/sets/combinations/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/combinations/images/overview.png -------------------------------------------------------------------------------- /src/algorithms/sets/fisher-yates/README.md: -------------------------------------------------------------------------------- 1 | # Fisher–Yates shuffle 2 | 3 | The Fisher–Yates shuffle is an algorithm for generating a random 4 | permutation of a finite sequence—in plain terms, the algorithm 5 | shuffles the sequence. The algorithm effectively puts all the 6 | elements into a hat; it continually determines the next element 7 | by randomly drawing an element from the hat until no elements 8 | remain. The algorithm produces an unbiased permutation: every 9 | permutation is equally likely. The modern version of the 10 | algorithm is efficient: it takes time proportional to the 11 | number of items being shuffled and shuffles them in place. 12 | 13 | ## References 14 | 15 | [Wikipedia](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) 16 | -------------------------------------------------------------------------------- /src/algorithms/sets/fisher-yates/__test__/fisherYates.test.js: -------------------------------------------------------------------------------- 1 | import fisherYates from '../fisherYates'; 2 | import { sortedArr } from '../../../sorting/SortTester'; 3 | import QuickSort from '../../../sorting/quick-sort/QuickSort'; 4 | 5 | describe('fisherYates', () => { 6 | it('should shuffle small arrays', () => { 7 | expect(fisherYates([])).toEqual([]); 8 | expect(fisherYates([1])).toEqual([1]); 9 | }); 10 | 11 | it('should shuffle array randomly', () => { 12 | const shuffledArray = fisherYates(sortedArr); 13 | const sorter = new QuickSort(); 14 | 15 | expect(shuffledArray.length).toBe(sortedArr.length); 16 | expect(shuffledArray).not.toEqual(sortedArr); 17 | expect(sorter.sort(shuffledArray)).toEqual(sortedArr); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/algorithms/sets/fisher-yates/fisherYates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {*[]} originalArray 3 | * @return {*[]} 4 | */ 5 | export default function fisherYates(originalArray) { 6 | // Clone array from preventing original array from modification (for testing purpose). 7 | const array = originalArray.slice(0); 8 | 9 | for (let i = (array.length - 1); i > 0; i -= 1) { 10 | const randomIndex = Math.floor(Math.random() * (i + 1)); 11 | [array[i], array[randomIndex]] = [array[randomIndex], array[i]]; 12 | } 13 | 14 | return array; 15 | } 16 | -------------------------------------------------------------------------------- /src/algorithms/sets/knapsack-problem/KnapsackItem.js: -------------------------------------------------------------------------------- 1 | export default class KnapsackItem { 2 | /** 3 | * @param {Object} itemSettings - knapsack item settings, 4 | * @param {number} itemSettings.value - value of the item. 5 | * @param {number} itemSettings.weight - weight of the item. 6 | * @param {number} itemSettings.itemsInStock - how many items are available to be added. 7 | */ 8 | constructor({ value, weight, itemsInStock = 1 }) { 9 | this.value = value; 10 | this.weight = weight; 11 | this.itemsInStock = itemsInStock; 12 | // Actual number of items that is going to be added to knapsack. 13 | this.quantity = 1; 14 | } 15 | 16 | get totalValue() { 17 | return this.value * this.quantity; 18 | } 19 | 20 | get totalWeight() { 21 | return this.weight * this.quantity; 22 | } 23 | 24 | // This coefficient shows how valuable the 1 unit of weight is 25 | // for current item. 26 | get valuePerWeightRatio() { 27 | return this.value / this.weight; 28 | } 29 | 30 | toString() { 31 | return `v${this.value} w${this.weight} x ${this.quantity}`; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/algorithms/sets/longest-common-subsequence/README.md: -------------------------------------------------------------------------------- 1 | # Longest common subsequence problem 2 | 3 | The longest common subsequence (LCS) problem is the problem of finding 4 | the longest subsequence common to all sequences in a set of sequences 5 | (often just two sequences). It differs from the longest common substring 6 | problem: unlike substrings, subsequences are not required to occupy 7 | consecutive positions within the original sequences. 8 | 9 | ## Application 10 | 11 | The longest common subsequence problem is a classic computer science 12 | problem, the basis of data comparison programs such as the diff utility, 13 | and has applications in bioinformatics. It is also widely used by 14 | revision control systems such as Git for reconciling multiple changes 15 | made to a revision-controlled collection of files. 16 | 17 | ## Example 18 | 19 | - LCS for input Sequences `ABCDGH` and `AEDFHR` is `ADH` of length 3. 20 | - LCS for input Sequences `AGGTAB` and `GXTXAYB` is `GTAB` of length 4. 21 | 22 | ## References 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem) 25 | - [YouTube](https://www.youtube.com/watch?v=NnD96abizww&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 26 | -------------------------------------------------------------------------------- /src/algorithms/sets/longest-common-subsequence/__test__/longestCommonSubsequence.test.js: -------------------------------------------------------------------------------- 1 | import longestCommonSubsequence from '../longestCommonSubsequence'; 2 | 3 | describe('longestCommonSubsequence', () => { 4 | it('should find longest common subsequence for two strings', () => { 5 | expect(longestCommonSubsequence([''], [''])).toEqual(['']); 6 | 7 | expect(longestCommonSubsequence([''], ['A', 'B', 'C'])).toEqual(['']); 8 | 9 | expect(longestCommonSubsequence(['A', 'B', 'C'], [''])).toEqual(['']); 10 | 11 | expect(longestCommonSubsequence( 12 | ['A', 'B', 'C'], 13 | ['D', 'E', 'F', 'G'], 14 | )).toEqual(['']); 15 | 16 | expect(longestCommonSubsequence( 17 | ['A', 'B', 'C', 'D', 'G', 'H'], 18 | ['A', 'E', 'D', 'F', 'H', 'R'], 19 | )).toEqual(['A', 'D', 'H']); 20 | 21 | expect(longestCommonSubsequence( 22 | ['A', 'G', 'G', 'T', 'A', 'B'], 23 | ['G', 'X', 'T', 'X', 'A', 'Y', 'B'], 24 | )).toEqual(['G', 'T', 'A', 'B']); 25 | 26 | expect(longestCommonSubsequence( 27 | ['A', 'B', 'C', 'D', 'A', 'F'], 28 | ['A', 'C', 'B', 'C', 'F'], 29 | )).toEqual(['A', 'B', 'C', 'F']); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/algorithms/sets/longest-common-subsequence/__test__/longestCommonSubsequenceRecursive.test.js: -------------------------------------------------------------------------------- 1 | import longestCommonSubsequence from '../longestCommonSubsequenceRecursive'; 2 | 3 | describe('longestCommonSubsequenceRecursive', () => { 4 | it('should find longest common substring between two strings', () => { 5 | expect(longestCommonSubsequence('', '')).toBe(''); 6 | expect(longestCommonSubsequence('ABC', '')).toBe(''); 7 | expect(longestCommonSubsequence('', 'ABC')).toBe(''); 8 | expect(longestCommonSubsequence('ABABC', 'BABCA')).toBe('BABC'); 9 | expect(longestCommonSubsequence('BABCA', 'ABCBA')).toBe('ABCA'); 10 | expect(longestCommonSubsequence('sea', 'eat')).toBe('ea'); 11 | expect(longestCommonSubsequence('algorithms', 'rithm')).toBe('rithm'); 12 | expect(longestCommonSubsequence( 13 | 'Algorithms and data structures implemented in JavaScript', 14 | 'Here you may find Algorithms and data structures that are implemented in JavaScript', 15 | )).toBe('Algorithms and data structures implemented in JavaScript'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/algorithms/sets/longest-common-subsequence/longestCommonSubsequenceRecursive.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-param-reassign */ 2 | /** 3 | * Longest Common Subsequence (LCS) (Recursive Approach). 4 | * 5 | * @param {string} string1 6 | * @param {string} string2 7 | * @return {number} 8 | */ 9 | export default function longestCommonSubsequenceRecursive(string1, string2) { 10 | /** 11 | * 12 | * @param {string} s1 13 | * @param {string} s2 14 | * @return {string} - returns the LCS (Longest Common Subsequence) 15 | */ 16 | const lcs = (s1, s2, memo = {}) => { 17 | if (!s1 || !s2) return ''; 18 | 19 | if (memo[`${s1}:${s2}`]) return memo[`${s1}:${s2}`]; 20 | 21 | if (s1[0] === s2[0]) { 22 | return s1[0] + lcs(s1.substring(1), s2.substring(1), memo); 23 | } 24 | 25 | const nextLcs1 = lcs(s1.substring(1), s2, memo); 26 | const nextLcs2 = lcs(s1, s2.substring(1), memo); 27 | 28 | const nextLongest = nextLcs1.length >= nextLcs2.length ? nextLcs1 : nextLcs2; 29 | 30 | memo[`${s1}:${s2}`] = nextLongest; 31 | 32 | return nextLongest; 33 | }; 34 | 35 | return lcs(string1, string2); 36 | } 37 | -------------------------------------------------------------------------------- /src/algorithms/sets/longest-increasing-subsequence/__test__/dpLongestIncreasingSubsequence.test.js: -------------------------------------------------------------------------------- 1 | import dpLongestIncreasingSubsequence from '../dpLongestIncreasingSubsequence'; 2 | 3 | describe('dpLongestIncreasingSubsequence', () => { 4 | it('should find longest increasing subsequence length', () => { 5 | // Should be: 6 | // 9 or 7 | // 8 or 8 | // 7 or 9 | // 6 or 10 | // ... 11 | expect(dpLongestIncreasingSubsequence([ 12 | 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 13 | ])).toBe(1); 14 | 15 | // Should be: 16 | // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 17 | expect(dpLongestIncreasingSubsequence([ 18 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 19 | ])).toBe(10); 20 | 21 | // Should be: 22 | // -1, 0, 2, 3 23 | expect(dpLongestIncreasingSubsequence([ 24 | 3, 4, -1, 0, 6, 2, 3, 25 | ])).toBe(4); 26 | 27 | // Should be: 28 | // 0, 2, 6, 9, 11, 15 or 29 | // 0, 4, 6, 9, 11, 15 or 30 | // 0, 2, 6, 9, 13, 15 or 31 | // 0, 4, 6, 9, 13, 15 32 | expect(dpLongestIncreasingSubsequence([ 33 | 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15, 34 | ])).toBe(6); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/algorithms/sets/maximum-subarray/__test__/bfMaximumSubarray.test.js: -------------------------------------------------------------------------------- 1 | import bfMaximumSubarray from '../bfMaximumSubarray'; 2 | 3 | describe('bfMaximumSubarray', () => { 4 | it('should find maximum subarray using the brute force algorithm', () => { 5 | expect(bfMaximumSubarray([])).toEqual([]); 6 | expect(bfMaximumSubarray([0, 0])).toEqual([0]); 7 | expect(bfMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]); 8 | expect(bfMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]); 9 | expect(bfMaximumSubarray([0, 0, -1, 2])).toEqual([2]); 10 | expect(bfMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]); 11 | expect(bfMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]); 12 | expect(bfMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]); 13 | expect(bfMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual([4, -1, -2, 1, 5]); 14 | expect(bfMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual([7, 6, -1, 4, 11]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/sets/maximum-subarray/__test__/dcMaximumSubarraySum.test.js: -------------------------------------------------------------------------------- 1 | import dcMaximumSubarray from '../dcMaximumSubarraySum'; 2 | 3 | describe('dcMaximumSubarraySum', () => { 4 | it('should find maximum subarray sum using the divide and conquer algorithm', () => { 5 | expect(dcMaximumSubarray([])).toEqual(-Infinity); 6 | expect(dcMaximumSubarray([0, 0])).toEqual(0); 7 | expect(dcMaximumSubarray([0, 0, 1])).toEqual(1); 8 | expect(dcMaximumSubarray([0, 0, 1, 2])).toEqual(3); 9 | expect(dcMaximumSubarray([0, 0, -1, 2])).toEqual(2); 10 | expect(dcMaximumSubarray([-1, -2, -3, -4, -5])).toEqual(-1); 11 | expect(dcMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual(20); 12 | expect(dcMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual(6); 13 | expect(dcMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual(7); 14 | expect(dcMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual(27); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/sets/maximum-subarray/__test__/dpMaximumSubarray.test.js: -------------------------------------------------------------------------------- 1 | import dpMaximumSubarray from '../dpMaximumSubarray'; 2 | 3 | describe('dpMaximumSubarray', () => { 4 | it('should find maximum subarray using the dynamic programming algorithm', () => { 5 | expect(dpMaximumSubarray([])).toEqual([]); 6 | expect(dpMaximumSubarray([0, 0])).toEqual([0]); 7 | expect(dpMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]); 8 | expect(dpMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]); 9 | expect(dpMaximumSubarray([0, 0, -1, 2])).toEqual([2]); 10 | expect(dpMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]); 11 | expect(dpMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]); 12 | expect(dpMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]); 13 | expect(dpMaximumSubarray([-2, -3, 4, -1, -2, 1, 5, -3])).toEqual([4, -1, -2, 1, 5]); 14 | expect(dpMaximumSubarray([1, -3, 2, -5, 7, 6, -1, 4, 11, -23])).toEqual([7, 6, -1, 4, 11]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/sets/maximum-subarray/bfMaximumSubarray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Brute Force solution. 3 | * Complexity: O(n^2) 4 | * 5 | * @param {Number[]} inputArray 6 | * @return {Number[]} 7 | */ 8 | export default function bfMaximumSubarray(inputArray) { 9 | let maxSubarrayStartIndex = 0; 10 | let maxSubarrayLength = 0; 11 | let maxSubarraySum = null; 12 | 13 | for (let startIndex = 0; startIndex < inputArray.length; startIndex += 1) { 14 | let subarraySum = 0; 15 | for (let arrLength = 1; arrLength <= (inputArray.length - startIndex); arrLength += 1) { 16 | subarraySum += inputArray[startIndex + (arrLength - 1)]; 17 | if (maxSubarraySum === null || subarraySum > maxSubarraySum) { 18 | maxSubarraySum = subarraySum; 19 | maxSubarrayStartIndex = startIndex; 20 | maxSubarrayLength = arrLength; 21 | } 22 | } 23 | } 24 | 25 | return inputArray.slice(maxSubarrayStartIndex, maxSubarrayStartIndex + maxSubarrayLength); 26 | } 27 | -------------------------------------------------------------------------------- /src/algorithms/sets/permutations/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/permutations/images/overview.png -------------------------------------------------------------------------------- /src/algorithms/sets/permutations/images/permutations-overview.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/permutations/images/permutations-overview.jpeg -------------------------------------------------------------------------------- /src/algorithms/sets/permutations/images/permutations-with-repetitions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/permutations/images/permutations-with-repetitions.jpg -------------------------------------------------------------------------------- /src/algorithms/sets/permutations/images/permutations-without-repetitions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sets/permutations/images/permutations-without-repetitions.jpg -------------------------------------------------------------------------------- /src/algorithms/sets/permutations/permutateWithRepetitions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {*[]} permutationOptions 3 | * @param {number} permutationLength 4 | * @return {*[]} 5 | */ 6 | export default function permutateWithRepetitions( 7 | permutationOptions, 8 | permutationLength = permutationOptions.length, 9 | ) { 10 | if (permutationLength === 1) { 11 | return permutationOptions.map((permutationOption) => [permutationOption]); 12 | } 13 | 14 | // Init permutations array. 15 | const permutations = []; 16 | 17 | // Get smaller permutations. 18 | const smallerPermutations = permutateWithRepetitions( 19 | permutationOptions, 20 | permutationLength - 1, 21 | ); 22 | 23 | // Go through all options and join it to the smaller permutations. 24 | permutationOptions.forEach((currentOption) => { 25 | smallerPermutations.forEach((smallerPermutation) => { 26 | permutations.push([currentOption].concat(smallerPermutation)); 27 | }); 28 | }); 29 | 30 | return permutations; 31 | } 32 | -------------------------------------------------------------------------------- /src/algorithms/sets/power-set/__test__/btPowerSet.test.js: -------------------------------------------------------------------------------- 1 | import btPowerSet from '../btPowerSet'; 2 | 3 | describe('btPowerSet', () => { 4 | it('should calculate power set of given set using backtracking approach', () => { 5 | expect(btPowerSet([1])).toEqual([ 6 | [], 7 | [1], 8 | ]); 9 | 10 | expect(btPowerSet([1, 2, 3])).toEqual([ 11 | [], 12 | [1], 13 | [1, 2], 14 | [1, 2, 3], 15 | [1, 3], 16 | [2], 17 | [2, 3], 18 | [3], 19 | ]); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/sets/power-set/__test__/bwPowerSet.test.js: -------------------------------------------------------------------------------- 1 | import bwPowerSet from '../bwPowerSet'; 2 | 3 | describe('bwPowerSet', () => { 4 | it('should calculate power set of given set using bitwise approach', () => { 5 | expect(bwPowerSet([1])).toEqual([ 6 | [], 7 | [1], 8 | ]); 9 | 10 | expect(bwPowerSet([1, 2, 3])).toEqual([ 11 | [], 12 | [1], 13 | [2], 14 | [1, 2], 15 | [3], 16 | [1, 3], 17 | [2, 3], 18 | [1, 2, 3], 19 | ]); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/sets/power-set/__test__/caPowerSet.test.js: -------------------------------------------------------------------------------- 1 | import caPowerSet from '../caPowerSet'; 2 | 3 | describe('caPowerSet', () => { 4 | it('should calculate power set of given set using cascading approach', () => { 5 | expect(caPowerSet([1])).toEqual([ 6 | [], 7 | [1], 8 | ]); 9 | 10 | expect(caPowerSet([1, 2])).toEqual([ 11 | [], 12 | [1], 13 | [2], 14 | [1, 2], 15 | ]); 16 | 17 | expect(caPowerSet([1, 2, 3])).toEqual([ 18 | [], 19 | [1], 20 | [2], 21 | [1, 2], 22 | [3], 23 | [1, 3], 24 | [2, 3], 25 | [1, 2, 3], 26 | ]); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/algorithms/sets/power-set/caPowerSet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Find power-set of a set using CASCADING approach. 3 | * 4 | * @param {*[]} originalSet 5 | * @return {*[][]} 6 | */ 7 | export default function caPowerSet(originalSet) { 8 | // Let's start with an empty set. 9 | const sets = [[]]; 10 | 11 | /* 12 | Now, let's say: 13 | originalSet = [1, 2, 3]. 14 | 15 | Let's add the first element from the originalSet to all existing sets: 16 | [[]] ← 1 = [[], [1]] 17 | 18 | Adding the 2nd element to all existing sets: 19 | [[], [1]] ← 2 = [[], [1], [2], [1, 2]] 20 | 21 | Adding the 3nd element to all existing sets: 22 | [[], [1], [2], [1, 2]] ← 3 = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] 23 | 24 | And so on for the rest of the elements from originalSet. 25 | On every iteration the number of sets is doubled, so we'll get 2^n sets. 26 | */ 27 | for (let numIdx = 0; numIdx < originalSet.length; numIdx += 1) { 28 | const existingSetsNum = sets.length; 29 | 30 | for (let setIdx = 0; setIdx < existingSetsNum; setIdx += 1) { 31 | const set = [...sets[setIdx], originalSet[numIdx]]; 32 | sets.push(set); 33 | } 34 | } 35 | 36 | return sets; 37 | } 38 | -------------------------------------------------------------------------------- /src/algorithms/sets/shortest-common-supersequence/README.md: -------------------------------------------------------------------------------- 1 | # Shortest Common Supersequence 2 | 3 | The shortest common supersequence (SCS) of two sequences `X` and `Y` 4 | is the shortest sequence which has `X` and `Y` as subsequences. 5 | 6 | In other words assume we're given two strings str1 and str2, find 7 | the shortest string that has both str1 and str2 as subsequences. 8 | 9 | This is a problem closely related to the longest common 10 | subsequence problem. 11 | 12 | ## Example 13 | 14 | ``` 15 | Input: str1 = "geek", str2 = "eke" 16 | Output: "geeke" 17 | 18 | Input: str1 = "AGGTAB", str2 = "GXTXAYB" 19 | Output: "AGXGTXAYB" 20 | ``` 21 | 22 | ## References 23 | 24 | - [GeeksForGeeks](https://www.geeksforgeeks.org/shortest-common-supersequence/) 25 | -------------------------------------------------------------------------------- /src/algorithms/sorting/Sort.js: -------------------------------------------------------------------------------- 1 | import Comparator from '../../utils/comparator/Comparator'; 2 | 3 | /** 4 | * @typedef {Object} SorterCallbacks 5 | * @property {function(a: *, b: *)} compareCallback - If provided then all elements comparisons 6 | * will be done through this callback. 7 | * @property {function(a: *)} visitingCallback - If provided it will be called each time the sorting 8 | * function is visiting the next element. 9 | */ 10 | 11 | export default class Sort { 12 | constructor(originalCallbacks) { 13 | this.callbacks = Sort.initSortingCallbacks(originalCallbacks); 14 | this.comparator = new Comparator(this.callbacks.compareCallback); 15 | } 16 | 17 | /** 18 | * @param {SorterCallbacks} originalCallbacks 19 | * @returns {SorterCallbacks} 20 | */ 21 | static initSortingCallbacks(originalCallbacks) { 22 | const callbacks = originalCallbacks || {}; 23 | const stubCallback = () => {}; 24 | 25 | callbacks.compareCallback = callbacks.compareCallback || undefined; 26 | callbacks.visitingCallback = callbacks.visitingCallback || stubCallback; 27 | 28 | return callbacks; 29 | } 30 | 31 | sort() { 32 | throw new Error('sort method must be implemented'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/algorithms/sorting/__test__/Sort.test.js: -------------------------------------------------------------------------------- 1 | import Sort from '../Sort'; 2 | 3 | describe('Sort', () => { 4 | it('should throw an error when trying to call Sort.sort() method directly', () => { 5 | function doForbiddenSort() { 6 | const sorter = new Sort(); 7 | sorter.sort(); 8 | } 9 | 10 | expect(doForbiddenSort).toThrow(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/sorting/bubble-sort/BubbleSort.js: -------------------------------------------------------------------------------- 1 | import Sort from '../Sort'; 2 | 3 | export default class BubbleSort extends Sort { 4 | sort(originalArray) { 5 | // Flag that holds info about whether the swap has occur or not. 6 | let swapped = false; 7 | // Clone original array to prevent its modification. 8 | const array = [...originalArray]; 9 | 10 | for (let i = 1; i < array.length; i += 1) { 11 | swapped = false; 12 | 13 | // Call visiting callback. 14 | this.callbacks.visitingCallback(array[i]); 15 | 16 | for (let j = 0; j < array.length - i; j += 1) { 17 | // Call visiting callback. 18 | this.callbacks.visitingCallback(array[j]); 19 | 20 | // Swap elements if they are in wrong order. 21 | if (this.comparator.lessThan(array[j + 1], array[j])) { 22 | [array[j], array[j + 1]] = [array[j + 1], array[j]]; 23 | 24 | // Register the swap. 25 | swapped = true; 26 | } 27 | } 28 | 29 | // If there were no swaps then array is already sorted and there is 30 | // no need to proceed. 31 | if (!swapped) { 32 | return array; 33 | } 34 | } 35 | 36 | return array; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/algorithms/sorting/bubble-sort/README.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort 2 | 3 | _Read this in other languages:_ 4 | [_Português_](README.pt-BR.md) 5 | 6 | Bubble sort, sometimes referred to as sinking sort, is a 7 | simple sorting algorithm that repeatedly steps through 8 | the list to be sorted, compares each pair of adjacent 9 | items and swaps them if they are in the wrong order 10 | (ascending or descending arrangement). The pass through 11 | the list is repeated until no swaps are needed, which 12 | indicates that the list is sorted. 13 | 14 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) 15 | 16 | ## Complexity 17 | 18 | | Name | Best | Average | Worst | Memory | Stable | Comments | 19 | | --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | 20 | | **Bubble sort** | n | n2 | n2 | 1 | Yes | | 21 | 22 | ## References 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) 25 | - [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 26 | -------------------------------------------------------------------------------- /src/algorithms/sorting/bubble-sort/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort 2 | 3 | _Leia isso em outros idiomas:_ 4 | [_English_](README.md) 5 | 6 | O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. 7 | 8 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) 9 | 10 | ## Complexidade 11 | 12 | | Nome | Melhor | Média | Pior | Memória | Estável | Comentários | 13 | | --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | 14 | | **Bubble sort** | n | n2 | n2 | 1 | Sim | | 15 | 16 | ## Referências 17 | 18 | - [Wikipedia](https://pt.wikipedia.org/wiki/Bubble_sort) 19 | - [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 20 | 21 | -------------------------------------------------------------------------------- /src/algorithms/sorting/bucket-sort/images/bucket_sort_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sorting/bucket-sort/images/bucket_sort_1.png -------------------------------------------------------------------------------- /src/algorithms/sorting/bucket-sort/images/bucket_sort_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sorting/bucket-sort/images/bucket_sort_2.png -------------------------------------------------------------------------------- /src/algorithms/sorting/heap-sort/HeapSort.js: -------------------------------------------------------------------------------- 1 | import Sort from '../Sort'; 2 | import MinHeap from '../../../data-structures/heap/MinHeap'; 3 | 4 | export default class HeapSort extends Sort { 5 | sort(originalArray) { 6 | const sortedArray = []; 7 | const minHeap = new MinHeap(this.callbacks.compareCallback); 8 | 9 | // Insert all array elements to the heap. 10 | originalArray.forEach((element) => { 11 | // Call visiting callback. 12 | this.callbacks.visitingCallback(element); 13 | 14 | minHeap.add(element); 15 | }); 16 | 17 | // Now we have min heap with minimal element always on top. 18 | // Let's poll that minimal element one by one and thus form the sorted array. 19 | while (!minHeap.isEmpty()) { 20 | const nextMinElement = minHeap.poll(); 21 | 22 | // Call visiting callback. 23 | this.callbacks.visitingCallback(nextMinElement); 24 | 25 | sortedArray.push(nextMinElement); 26 | } 27 | 28 | return sortedArray; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/algorithms/sorting/insertion-sort/InsertionSort.js: -------------------------------------------------------------------------------- 1 | import Sort from '../Sort'; 2 | 3 | export default class InsertionSort extends Sort { 4 | sort(originalArray) { 5 | const array = [...originalArray]; 6 | 7 | // Go through all array elements... 8 | for (let i = 1; i < array.length; i += 1) { 9 | let currentIndex = i; 10 | 11 | // Call visiting callback. 12 | this.callbacks.visitingCallback(array[i]); 13 | 14 | // Check if previous element is greater than current element. 15 | // If so, swap the two elements. 16 | while ( 17 | array[currentIndex - 1] !== undefined 18 | && this.comparator.lessThan(array[currentIndex], array[currentIndex - 1]) 19 | ) { 20 | // Call visiting callback. 21 | this.callbacks.visitingCallback(array[currentIndex - 1]); 22 | 23 | // Swap the elements. 24 | [ 25 | array[currentIndex - 1], 26 | array[currentIndex], 27 | ] = [ 28 | array[currentIndex], 29 | array[currentIndex - 1], 30 | ]; 31 | 32 | // Shift current index left. 33 | currentIndex -= 1; 34 | } 35 | } 36 | 37 | return array; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/algorithms/sorting/insertion-sort/README.md: -------------------------------------------------------------------------------- 1 | # Insertion Sort 2 | 3 | _Read this in other languages:_ 4 | [_Português_](README.pt-BR.md) 5 | 6 | Insertion sort is a simple sorting algorithm that builds 7 | the final sorted array (or list) one item at a time. 8 | It is much less efficient on large lists than more 9 | advanced algorithms such as quicksort, heapsort, or merge 10 | sort. 11 | 12 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif) 13 | 14 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif) 15 | 16 | ## Complexity 17 | 18 | | Name | Best | Average | Worst | Memory | Stable | Comments | 19 | | --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | 20 | | **Insertion sort** | n | n2 | n2 | 1 | Yes | | 21 | 22 | ## References 23 | 24 | [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort) 25 | -------------------------------------------------------------------------------- /src/algorithms/sorting/insertion-sort/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Insertion Sort 2 | 3 | _Leia isso em outros idiomas:_ 4 | [_English_](README.md) 5 | 6 | A ordenação por inserção é um algoritmo de ordenação simples que criaa matriz classificada final (ou lista) um item de cada vez. 7 | É muito menos eficiente em grandes listas do que mais algoritmos avançados, como quicksort, heapsort ou merge 8 | ordenar. 9 | 10 | ![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/4/42/Insertion_sort.gif) 11 | 12 | ![Visualização do Algoritmo](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif) 13 | 14 | ## Complexidade 15 | 16 | | Nome | Melhor | Média | Pior | Memória | Estável | Comentários | 17 | | --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | 18 | | **Insertion sort** | n | n2 | n2 | 1 | Sim | | 19 | 20 | ## Referências 21 | 22 | [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort) 23 | -------------------------------------------------------------------------------- /src/algorithms/sorting/merge-sort/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # 병합 정렬 2 | 3 | 컴퓨터과학에서, 병합 정렬(일반적으로 mergesort라고 쓰는)은 효율적이고, 범용적인, 비교 기반의 정렬 알고리즘입니다. 대부분의 구현들은 안정적인 정렬을 만들어내며, 이는 정렬된 산출물에서 동일한 요소들의 입력 순서가 유지된다는 것을 의미합니다. 병합 정렬은 1945년에 John von Neumann이 만든 분할 정복 알고리즘입니다. 4 | 5 | 병합 정렬의 예시입니다. 우선 리스트를 가장 작은 단위로 나누고(한 개의 요소), 두 개의 인접한 리스트를 정렬하고 병합하기 위해 각 요소와 인접한 리스트를 비교합니다. 마지막으로 모든 요소들은 정렬되고 병합됩니다. 6 | 7 | ![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/c/cc/Merge-sort-example-300px.gif) 8 | 9 | 재귀적인 병합 정렬 알고리즘은 7개의 정수값을 가진 배열을 정렬하는데 사용됩니다. 다음은 합병 정렬을 모방하기 위해 사람이 취하는 단계입니다.(하향식) 10 | 11 | ![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg) 12 | 13 | ## 복잡도 14 | 15 | | Name | Best | Average | Worst | Memory | Stable | Comments | 16 | | --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | 17 | | **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes | | 18 | 19 | ## 참조 20 | 21 | - [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort) 22 | - [YouTube](https://www.youtube.com/watch?v=KF2j-9iSf4Q&index=27&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/algorithms/sorting/quick-sort/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 快速排序 2 | 3 | 快速排序是一种分而治之的算法。快速排序首先将一个大数组分成两个较小的子数组:比某个数小的元素和比某个数大的元素。然后快速排序可以递归地对子数组进行排序。 4 | 5 | 步骤是: 6 | 7 | 1. 从数组中选择一个元素,称为基点 8 | 9 | 2. 分区:对数组重新排序,使所有值小于基点的元素都在它左边,而所有值大于基点的元素都在它右边(相等的值可以放在任何一边)。在此分区之后,基点处于其最终位置(左边和右边的中间位置)。这称为分区操作。 10 | 11 | 3. 递归地将上述步骤应用于左边的数组和右边的数组。 12 | 13 | 快速排序算法的动画可视化。水平线是基点值。 14 | 15 | ![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif) 16 | 17 | ## 复杂度 18 | 19 | | Name | Best | Average | Worst | Memory | Stable | Comments | 20 | | -------------- | :-----------: | :-----------: | :-----------: | :----: | :----: | :------------------------------------------------------------ | 21 | | **Quick sort** | n log(n) | n log(n) | n2 | log(n) | No | Quicksort is usually done in-place with O(log(n)) stack space | 22 | 23 | ## 引用 24 | 25 | - [Wikipedia](https://en.wikipedia.org/wiki/Quicksort) 26 | 27 | - [YouTube](https://www.youtube.com/watch?v=SLauY6PpjW4&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 28 | -------------------------------------------------------------------------------- /src/algorithms/sorting/radix-sort/__test__/RadixSort.test.js: -------------------------------------------------------------------------------- 1 | import RadixSort from '../RadixSort'; 2 | import { SortTester } from '../../SortTester'; 3 | 4 | // Complexity constants. 5 | const ARRAY_OF_STRINGS_VISIT_COUNT = 24; 6 | const ARRAY_OF_INTEGERS_VISIT_COUNT = 77; 7 | describe('RadixSort', () => { 8 | it('should sort array', () => { 9 | SortTester.testSort(RadixSort); 10 | }); 11 | 12 | it('should visit array of strings n (number of strings) x m (length of longest element) times', () => { 13 | SortTester.testAlgorithmTimeComplexity( 14 | RadixSort, 15 | ['zzz', 'bb', 'a', 'rr', 'rrb', 'rrba'], 16 | ARRAY_OF_STRINGS_VISIT_COUNT, 17 | ); 18 | }); 19 | 20 | it('should visit array of integers n (number of elements) x m (length of longest integer) times', () => { 21 | SortTester.testAlgorithmTimeComplexity( 22 | RadixSort, 23 | [3, 1, 75, 32, 884, 523, 4343456, 232, 123, 656, 343], 24 | ARRAY_OF_INTEGERS_VISIT_COUNT, 25 | ); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/algorithms/sorting/radix-sort/images/radix-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/sorting/radix-sort/images/radix-sort.png -------------------------------------------------------------------------------- /src/algorithms/sorting/selection-sort/SelectionSort.js: -------------------------------------------------------------------------------- 1 | import Sort from '../Sort'; 2 | 3 | export default class SelectionSort extends Sort { 4 | sort(originalArray) { 5 | // Clone original array to prevent its modification. 6 | const array = [...originalArray]; 7 | 8 | for (let i = 0; i < array.length - 1; i += 1) { 9 | let minIndex = i; 10 | 11 | // Call visiting callback. 12 | this.callbacks.visitingCallback(array[i]); 13 | 14 | // Find minimum element in the rest of array. 15 | for (let j = i + 1; j < array.length; j += 1) { 16 | // Call visiting callback. 17 | this.callbacks.visitingCallback(array[j]); 18 | 19 | if (this.comparator.lessThan(array[j], array[minIndex])) { 20 | minIndex = j; 21 | } 22 | } 23 | 24 | // If new minimum element has been found then swap it with current i-th element. 25 | if (minIndex !== i) { 26 | [array[i], array[minIndex]] = [array[minIndex], array[i]]; 27 | } 28 | } 29 | 30 | return array; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/algorithms/stack/valid-parentheses/__test__/validParentheses.test.js: -------------------------------------------------------------------------------- 1 | import isValid from '../validParentheses'; 2 | 3 | describe('validParentheses', () => { 4 | it('should return false when string is empty', () => { 5 | expect(isValid('')).toBe(false); 6 | }); 7 | 8 | it('should return true when string contains valid parentheses in correct order', () => { 9 | expect(isValid('()')).toBe(true); 10 | expect(isValid('()[]{}')).toBe(true); 11 | expect(isValid('((({[]})))')).toBe(true); 12 | }); 13 | 14 | it('should return false when string contains invalid parentheses', () => { 15 | expect(isValid('(]')).toBe(false); 16 | expect(isValid('()[]{} }')).toBe(false); 17 | expect(isValid('((({[(]})))')).toBe(false); 18 | }); 19 | 20 | it('should return false when string contains valid parentheses in wrong order', () => { 21 | expect(isValid('({)}')).toBe(false); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/algorithms/statistics/weighted-random/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/algorithms/statistics/weighted-random/images/cover.png -------------------------------------------------------------------------------- /src/algorithms/string/hamming-distance/README.md: -------------------------------------------------------------------------------- 1 | # Hamming Distance 2 | 3 | the Hamming distance between two strings of equal length is the 4 | number of positions at which the corresponding symbols are 5 | different. In other words, it measures the minimum number of 6 | substitutions required to change one string into the other, or 7 | the minimum number of errors that could have transformed one 8 | string into the other. In a more general context, the Hamming 9 | distance is one of several string metrics for measuring the 10 | edit distance between two sequences. 11 | 12 | ## Examples 13 | 14 | The Hamming distance between: 15 | 16 | - "ka**rol**in" and "ka**thr**in" is **3**. 17 | - "k**a**r**ol**in" and "k**e**r**st**in" is **3**. 18 | - 10**1**1**1**01 and 10**0**1**0**01 is **2**. 19 | - 2**17**3**8**96 and 2**23**3**7**96 is **3**. 20 | 21 | ## References 22 | 23 | [Wikipedia](https://en.wikipedia.org/wiki/Hamming_distance) 24 | -------------------------------------------------------------------------------- /src/algorithms/string/hamming-distance/__test__/hammingDistance.test.js: -------------------------------------------------------------------------------- 1 | import hammingDistance from '../hammingDistance'; 2 | 3 | describe('hammingDistance', () => { 4 | it('should throw an error when trying to compare the strings of different lengths', () => { 5 | const compareStringsOfDifferentLength = () => { 6 | hammingDistance('a', 'aa'); 7 | }; 8 | 9 | expect(compareStringsOfDifferentLength).toThrowError(); 10 | }); 11 | 12 | it('should calculate difference between two strings', () => { 13 | expect(hammingDistance('a', 'a')).toBe(0); 14 | expect(hammingDistance('a', 'b')).toBe(1); 15 | expect(hammingDistance('abc', 'add')).toBe(2); 16 | expect(hammingDistance('karolin', 'kathrin')).toBe(3); 17 | expect(hammingDistance('karolin', 'kerstin')).toBe(3); 18 | expect(hammingDistance('1011101', '1001001')).toBe(2); 19 | expect(hammingDistance('2173896', '2233796')).toBe(3); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/string/hamming-distance/hammingDistance.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} a 3 | * @param {string} b 4 | * @return {number} 5 | */ 6 | export default function hammingDistance(a, b) { 7 | if (a.length !== b.length) { 8 | throw new Error('Strings must be of the same length'); 9 | } 10 | 11 | let distance = 0; 12 | 13 | for (let i = 0; i < a.length; i += 1) { 14 | if (a[i] !== b[i]) { 15 | distance += 1; 16 | } 17 | } 18 | 19 | return distance; 20 | } 21 | -------------------------------------------------------------------------------- /src/algorithms/string/knuth-morris-pratt/README.md: -------------------------------------------------------------------------------- 1 | # Knuth–Morris–Pratt Algorithm 2 | 3 | The Knuth–Morris–Pratt string searching algorithm (or 4 | KMP algorithm) searches for occurrences of a "word" `W` 5 | within a main "text string" `T` by employing the 6 | observation that when a mismatch occurs, the word itself 7 | embodies sufficient information to determine where the 8 | next match could begin, thus bypassing re-examination 9 | of previously matched characters. 10 | 11 | ## Complexity 12 | 13 | - **Time:** `O(|W| + |T|)` (much faster comparing to trivial `O(|W| * |T|)`) 14 | - **Space:** `O(|W|)` 15 | 16 | ## References 17 | 18 | - [Wikipedia](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm) 19 | - [YouTube](https://www.youtube.com/watch?v=GTJr8OvyEVQ&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 20 | -------------------------------------------------------------------------------- /src/algorithms/string/knuth-morris-pratt/__test__/knuthMorrisPratt.test.js: -------------------------------------------------------------------------------- 1 | import knuthMorrisPratt from '../knuthMorrisPratt'; 2 | 3 | describe('knuthMorrisPratt', () => { 4 | it('should find word position in given text', () => { 5 | expect(knuthMorrisPratt('', '')).toBe(0); 6 | expect(knuthMorrisPratt('a', '')).toBe(0); 7 | expect(knuthMorrisPratt('a', 'a')).toBe(0); 8 | expect(knuthMorrisPratt('abcbcglx', 'abca')).toBe(-1); 9 | expect(knuthMorrisPratt('abcbcglx', 'bcgl')).toBe(3); 10 | expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toBe(15); 11 | expect(knuthMorrisPratt('abcxabcdabxabcdabcdabcy', 'abcdabca')).toBe(-1); 12 | expect(knuthMorrisPratt('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toBe(12); 13 | expect(knuthMorrisPratt('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toBe(11); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algorithms/string/longest-common-substring/README.md: -------------------------------------------------------------------------------- 1 | # Longest Common Substring Problem 2 | 3 | The longest common substring problem is to find the longest string 4 | (or strings) that is a substring (or are substrings) of two or more 5 | strings. 6 | 7 | ## Example 8 | 9 | The longest common substring of the strings `ABABC`, `BABCA` and 10 | `ABCBA` is string `ABC` of length 3. Other common substrings are 11 | `A`, `AB`, `B`, `BA`, `BC` and `C`. 12 | 13 | ``` 14 | ABABC 15 | ||| 16 | BABCA 17 | ||| 18 | ABCBA 19 | ``` 20 | 21 | ## References 22 | 23 | - [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_substring_problem) 24 | - [YouTube](https://www.youtube.com/watch?v=BysNXJHzCEs&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 25 | -------------------------------------------------------------------------------- /src/algorithms/string/palindrome/README.md: -------------------------------------------------------------------------------- 1 | # Palindrome Check 2 | 3 | A [Palindrome](https://en.wikipedia.org/wiki/Palindrome) is a string that reads the same forwards and backwards. 4 | This means that the second half of the string is the reverse of the 5 | first half. 6 | 7 | ## Examples 8 | 9 | The following are palindromes (thus would return `TRUE`): 10 | 11 | ``` 12 | - "a" 13 | - "pop" -> p + o + p 14 | - "deed" -> de + ed 15 | - "kayak" -> ka + y + ak 16 | - "racecar" -> rac + e + car 17 | ``` 18 | 19 | The following are NOT palindromes (thus would return `FALSE`): 20 | 21 | ``` 22 | - "rad" 23 | - "dodo" 24 | - "polo" 25 | ``` 26 | 27 | ## References 28 | 29 | - [GeeksForGeeks - Check if a number is Palindrome](https://www.geeksforgeeks.org/check-if-a-number-is-palindrome/) 30 | -------------------------------------------------------------------------------- /src/algorithms/string/palindrome/__test__/isPalindrome.test.js: -------------------------------------------------------------------------------- 1 | import isPalindrome from '../isPalindrome'; 2 | 3 | describe('palindromeCheck', () => { 4 | it('should return whether or not the string is a palindrome', () => { 5 | expect(isPalindrome('a')).toBe(true); 6 | expect(isPalindrome('pop')).toBe(true); 7 | expect(isPalindrome('deed')).toBe(true); 8 | expect(isPalindrome('kayak')).toBe(true); 9 | expect(isPalindrome('racecar')).toBe(true); 10 | 11 | expect(isPalindrome('rad')).toBe(false); 12 | expect(isPalindrome('dodo')).toBe(false); 13 | expect(isPalindrome('polo')).toBe(false); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algorithms/string/palindrome/isPalindrome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} string 3 | * @return {boolean} 4 | */ 5 | 6 | export default function isPalindrome(string) { 7 | let left = 0; 8 | let right = string.length - 1; 9 | 10 | while (left < right) { 11 | if (string[left] !== string[right]) { 12 | return false; 13 | } 14 | left += 1; 15 | right -= 1; 16 | } 17 | 18 | return true; 19 | } 20 | -------------------------------------------------------------------------------- /src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js: -------------------------------------------------------------------------------- 1 | import zAlgorithm from '../zAlgorithm'; 2 | 3 | describe('zAlgorithm', () => { 4 | it('should find word positions in given text', () => { 5 | expect(zAlgorithm('abcbcglx', 'abca')).toEqual([]); 6 | expect(zAlgorithm('abca', 'abca')).toEqual([0]); 7 | expect(zAlgorithm('abca', 'abcadfd')).toEqual([]); 8 | expect(zAlgorithm('abcbcglabcx', 'abc')).toEqual([0, 7]); 9 | expect(zAlgorithm('abcbcglx', 'bcgl')).toEqual([3]); 10 | expect(zAlgorithm('abcbcglx', 'cglx')).toEqual([4]); 11 | expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toEqual([15]); 12 | expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabca')).toEqual([]); 13 | expect(zAlgorithm('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toEqual([12]); 14 | expect(zAlgorithm('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toEqual([11]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/tree/depth-first-search/README.md: -------------------------------------------------------------------------------- 1 | # Depth-First Search (DFS) 2 | 3 | Depth-first search (DFS) is an algorithm for traversing or 4 | searching tree or graph data structures. One starts at 5 | the root (selecting some arbitrary node as the root in 6 | the case of a graph) and explores as far as possible 7 | along each branch before backtracking. 8 | 9 | ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif) 10 | 11 | ## References 12 | 13 | - [Wikipedia](https://en.wikipedia.org/wiki/Depth-first_search) 14 | - [Tree Traversals (Inorder, Preorder and Postorder)](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/) 15 | - [BFS vs DFS](https://www.geeksforgeeks.org/bfs-vs-dfs-binary-tree/) 16 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finds the maximum profit from selling and buying the stocks. 3 | * ACCUMULATOR APPROACH. 4 | * 5 | * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] 6 | * @param {function(): void} visit - Visiting callback to calculate the number of iterations. 7 | * @return {number} - The maximum profit 8 | */ 9 | const accumulatorBestTimeToBuySellStocks = (prices, visit = () => {}) => { 10 | visit(); 11 | let profit = 0; 12 | for (let day = 1; day < prices.length; day += 1) { 13 | visit(); 14 | // Add the increase of the price from yesterday till today (if there was any) to the profit. 15 | profit += Math.max(prices[day] - prices[day - 1], 0); 16 | } 17 | return profit; 18 | }; 19 | 20 | export default accumulatorBestTimeToBuySellStocks; 21 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finds the maximum profit from selling and buying the stocks. 3 | * DYNAMIC PROGRAMMING APPROACH. 4 | * 5 | * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] 6 | * @param {function(): void} visit - Visiting callback to calculate the number of iterations. 7 | * @return {number} - The maximum profit 8 | */ 9 | const dpBestTimeToBuySellStocks = (prices, visit = () => {}) => { 10 | visit(); 11 | let lastBuy = -prices[0]; 12 | let lastSold = 0; 13 | 14 | for (let day = 1; day < prices.length; day += 1) { 15 | visit(); 16 | const curBuy = Math.max(lastBuy, lastSold - prices[day]); 17 | const curSold = Math.max(lastSold, lastBuy + prices[day]); 18 | lastBuy = curBuy; 19 | lastSold = curSold; 20 | } 21 | 22 | return lastSold; 23 | }; 24 | 25 | export default dpBestTimeToBuySellStocks; 26 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Finds the maximum profit from selling and buying the stocks. 3 | * PEAK VALLEY APPROACH. 4 | * 5 | * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] 6 | * @param {function(): void} visit - Visiting callback to calculate the number of iterations. 7 | * @return {number} - The maximum profit 8 | */ 9 | const peakvalleyBestTimeToBuySellStocks = (prices, visit = () => {}) => { 10 | visit(); 11 | let profit = 0; 12 | let low = prices[0]; 13 | let high = prices[0]; 14 | 15 | prices.slice(1).forEach((currentPrice) => { 16 | visit(); 17 | if (currentPrice < high) { 18 | // If price went down, we need to sell. 19 | profit += high - low; 20 | low = currentPrice; 21 | high = currentPrice; 22 | } else { 23 | // If price went up, we don't need to do anything but increase a high record. 24 | high = currentPrice; 25 | } 26 | }); 27 | 28 | // In case if price went up during the last day 29 | // and we didn't have chance to sell inside the forEach loop. 30 | profit += high - low; 31 | 32 | return profit; 33 | }; 34 | 35 | export default peakvalleyBestTimeToBuySellStocks; 36 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/jump-game/__test__/backtrackingJumpGame.test.js: -------------------------------------------------------------------------------- 1 | import backtrackingJumpGame from '../backtrackingJumpGame'; 2 | 3 | describe('backtrackingJumpGame', () => { 4 | it('should solve Jump Game problem in backtracking manner', () => { 5 | expect(backtrackingJumpGame([1, 0])).toBe(true); 6 | expect(backtrackingJumpGame([100, 0])).toBe(true); 7 | expect(backtrackingJumpGame([2, 3, 1, 1, 4])).toBe(true); 8 | expect(backtrackingJumpGame([1, 1, 1, 1, 1])).toBe(true); 9 | expect(backtrackingJumpGame([1, 1, 1, 10, 1])).toBe(true); 10 | expect(backtrackingJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true); 11 | 12 | expect(backtrackingJumpGame([1, 0, 1])).toBe(false); 13 | expect(backtrackingJumpGame([3, 2, 1, 0, 4])).toBe(false); 14 | expect(backtrackingJumpGame([0, 0, 0, 0, 0])).toBe(false); 15 | expect(backtrackingJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/jump-game/__test__/dpBottomUpJumpGame.test.js: -------------------------------------------------------------------------------- 1 | import dpBottomUpJumpGame from '../dpBottomUpJumpGame'; 2 | 3 | describe('dpBottomUpJumpGame', () => { 4 | it('should solve Jump Game problem in bottom-up dynamic programming manner', () => { 5 | expect(dpBottomUpJumpGame([1, 0])).toBe(true); 6 | expect(dpBottomUpJumpGame([100, 0])).toBe(true); 7 | expect(dpBottomUpJumpGame([2, 3, 1, 1, 4])).toBe(true); 8 | expect(dpBottomUpJumpGame([1, 1, 1, 1, 1])).toBe(true); 9 | expect(dpBottomUpJumpGame([1, 1, 1, 10, 1])).toBe(true); 10 | expect(dpBottomUpJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true); 11 | 12 | expect(dpBottomUpJumpGame([1, 0, 1])).toBe(false); 13 | expect(dpBottomUpJumpGame([3, 2, 1, 0, 4])).toBe(false); 14 | expect(dpBottomUpJumpGame([0, 0, 0, 0, 0])).toBe(false); 15 | expect(dpBottomUpJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/jump-game/__test__/dpTopDownJumpGame.test.js: -------------------------------------------------------------------------------- 1 | import dpTopDownJumpGame from '../dpTopDownJumpGame'; 2 | 3 | describe('dpTopDownJumpGame', () => { 4 | it('should solve Jump Game problem in top-down dynamic programming manner', () => { 5 | expect(dpTopDownJumpGame([1, 0])).toBe(true); 6 | expect(dpTopDownJumpGame([100, 0])).toBe(true); 7 | expect(dpTopDownJumpGame([2, 3, 1, 1, 4])).toBe(true); 8 | expect(dpTopDownJumpGame([1, 1, 1, 1, 1])).toBe(true); 9 | expect(dpTopDownJumpGame([1, 1, 1, 10, 1])).toBe(true); 10 | expect(dpTopDownJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true); 11 | 12 | expect(dpTopDownJumpGame([1, 0, 1])).toBe(false); 13 | expect(dpTopDownJumpGame([3, 2, 1, 0, 4])).toBe(false); 14 | expect(dpTopDownJumpGame([0, 0, 0, 0, 0])).toBe(false); 15 | expect(dpTopDownJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/jump-game/__test__/greedyJumpGame.test.js: -------------------------------------------------------------------------------- 1 | import greedyJumpGame from '../greedyJumpGame'; 2 | 3 | describe('greedyJumpGame', () => { 4 | it('should solve Jump Game problem in greedy manner', () => { 5 | expect(greedyJumpGame([1, 0])).toBe(true); 6 | expect(greedyJumpGame([100, 0])).toBe(true); 7 | expect(greedyJumpGame([2, 3, 1, 1, 4])).toBe(true); 8 | expect(greedyJumpGame([1, 1, 1, 1, 1])).toBe(true); 9 | expect(greedyJumpGame([1, 1, 1, 10, 1])).toBe(true); 10 | expect(greedyJumpGame([1, 5, 2, 1, 0, 2, 0])).toBe(true); 11 | 12 | expect(greedyJumpGame([1, 0, 1])).toBe(false); 13 | expect(greedyJumpGame([3, 2, 1, 0, 4])).toBe(false); 14 | expect(greedyJumpGame([0, 0, 0, 0, 0])).toBe(false); 15 | expect(greedyJumpGame([5, 4, 3, 2, 1, 0, 0])).toBe(false); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/knight-tour/__test__/knightTour.test.js: -------------------------------------------------------------------------------- 1 | import knightTour from '../knightTour'; 2 | 3 | describe('knightTour', () => { 4 | it('should not find solution on 3x3 board', () => { 5 | const moves = knightTour(3); 6 | 7 | expect(moves.length).toBe(0); 8 | }); 9 | 10 | it('should find one solution to do knight tour on 5x5 board', () => { 11 | const moves = knightTour(5); 12 | 13 | expect(moves.length).toBe(25); 14 | 15 | expect(moves).toEqual([ 16 | [0, 0], 17 | [1, 2], 18 | [2, 0], 19 | [0, 1], 20 | [1, 3], 21 | [3, 4], 22 | [2, 2], 23 | [4, 1], 24 | [3, 3], 25 | [1, 4], 26 | [0, 2], 27 | [1, 0], 28 | [3, 1], 29 | [4, 3], 30 | [2, 4], 31 | [0, 3], 32 | [1, 1], 33 | [3, 0], 34 | [4, 2], 35 | [2, 1], 36 | [4, 0], 37 | [3, 2], 38 | [4, 4], 39 | [2, 3], 40 | [0, 4], 41 | ]); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/n-queens/__test__/QueensPosition.test.js: -------------------------------------------------------------------------------- 1 | import QueenPosition from '../QueenPosition'; 2 | 3 | describe('QueenPosition', () => { 4 | it('should store queen position on chessboard', () => { 5 | const position1 = new QueenPosition(0, 0); 6 | const position2 = new QueenPosition(2, 1); 7 | 8 | expect(position2.columnIndex).toBe(1); 9 | expect(position2.rowIndex).toBe(2); 10 | expect(position1.leftDiagonal).toBe(0); 11 | expect(position1.rightDiagonal).toBe(0); 12 | expect(position2.leftDiagonal).toBe(1); 13 | expect(position2.rightDiagonal).toBe(3); 14 | expect(position2.toString()).toBe('2,1'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/n-queens/__test__/nQueensBitwise.test.js: -------------------------------------------------------------------------------- 1 | import nQueensBitwise from '../nQueensBitwise'; 2 | 3 | describe('nQueensBitwise', () => { 4 | it('should have solutions for 4 to N queens', () => { 5 | expect(nQueensBitwise(4)).toBe(2); 6 | expect(nQueensBitwise(5)).toBe(10); 7 | expect(nQueensBitwise(6)).toBe(4); 8 | expect(nQueensBitwise(7)).toBe(40); 9 | expect(nQueensBitwise(8)).toBe(92); 10 | expect(nQueensBitwise(9)).toBe(352); 11 | expect(nQueensBitwise(10)).toBe(724); 12 | expect(nQueensBitwise(11)).toBe(2680); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/rain-terraces/__test__/bfRainTerraces.test.js: -------------------------------------------------------------------------------- 1 | import bfRainTerraces from '../bfRainTerraces'; 2 | 3 | describe('bfRainTerraces', () => { 4 | it('should find the amount of water collected after raining', () => { 5 | expect(bfRainTerraces([1])).toBe(0); 6 | expect(bfRainTerraces([1, 0])).toBe(0); 7 | expect(bfRainTerraces([0, 1])).toBe(0); 8 | expect(bfRainTerraces([0, 1, 0])).toBe(0); 9 | expect(bfRainTerraces([0, 1, 0, 0])).toBe(0); 10 | expect(bfRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2); 11 | expect(bfRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2); 12 | expect(bfRainTerraces([2, 0, 2])).toBe(2); 13 | expect(bfRainTerraces([2, 0, 5])).toBe(2); 14 | expect(bfRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10); 15 | expect(bfRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6); 16 | expect(bfRainTerraces([1, 1, 1, 1, 1])).toBe(0); 17 | expect(bfRainTerraces([1, 2, 3, 4, 5])).toBe(0); 18 | expect(bfRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4); 19 | expect(bfRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/rain-terraces/__test__/dpRainTerraces.test.js: -------------------------------------------------------------------------------- 1 | import dpRainTerraces from '../dpRainTerraces'; 2 | 3 | describe('dpRainTerraces', () => { 4 | it('should find the amount of water collected after raining', () => { 5 | expect(dpRainTerraces([1])).toBe(0); 6 | expect(dpRainTerraces([1, 0])).toBe(0); 7 | expect(dpRainTerraces([0, 1])).toBe(0); 8 | expect(dpRainTerraces([0, 1, 0])).toBe(0); 9 | expect(dpRainTerraces([0, 1, 0, 0])).toBe(0); 10 | expect(dpRainTerraces([0, 1, 0, 0, 1, 0])).toBe(2); 11 | expect(dpRainTerraces([0, 2, 0, 0, 1, 0])).toBe(2); 12 | expect(dpRainTerraces([2, 0, 2])).toBe(2); 13 | expect(dpRainTerraces([2, 0, 5])).toBe(2); 14 | expect(dpRainTerraces([3, 0, 0, 2, 0, 4])).toBe(10); 15 | expect(dpRainTerraces([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])).toBe(6); 16 | expect(dpRainTerraces([1, 1, 1, 1, 1])).toBe(0); 17 | expect(dpRainTerraces([1, 2, 3, 4, 5])).toBe(0); 18 | expect(dpRainTerraces([4, 1, 3, 1, 2, 1, 2, 1])).toBe(4); 19 | expect(dpRainTerraces([0, 2, 4, 3, 4, 2, 4, 0, 8, 7, 0])).toBe(7); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/README.md: -------------------------------------------------------------------------------- 1 | # Recursive Staircase Problem 2 | 3 | ## The Problem 4 | 5 | There are `n` stairs, a person standing at the bottom wants to reach the top. The person can climb either `1` or `2` stairs at a time. _Count the number of ways, the person can reach the top._ 6 | 7 | ![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png) 8 | 9 | ## The Solution 10 | 11 | This is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms. 12 | 13 | - [Brute Force Recursive Solution](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)` 14 | - [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)` 15 | - [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)` 16 | - [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)` 17 | 18 | ## References 19 | 20 | - [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s) 21 | - [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/) 22 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseBF.test.js: -------------------------------------------------------------------------------- 1 | import recursiveStaircaseBF from '../recursiveStaircaseBF'; 2 | 3 | describe('recursiveStaircaseBF', () => { 4 | it('should calculate number of variants using Brute Force solution', () => { 5 | expect(recursiveStaircaseBF(-1)).toBe(0); 6 | expect(recursiveStaircaseBF(0)).toBe(0); 7 | expect(recursiveStaircaseBF(1)).toBe(1); 8 | expect(recursiveStaircaseBF(2)).toBe(2); 9 | expect(recursiveStaircaseBF(3)).toBe(3); 10 | expect(recursiveStaircaseBF(4)).toBe(5); 11 | expect(recursiveStaircaseBF(5)).toBe(8); 12 | expect(recursiveStaircaseBF(6)).toBe(13); 13 | expect(recursiveStaircaseBF(7)).toBe(21); 14 | expect(recursiveStaircaseBF(8)).toBe(34); 15 | expect(recursiveStaircaseBF(9)).toBe(55); 16 | expect(recursiveStaircaseBF(10)).toBe(89); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseDP.test.js: -------------------------------------------------------------------------------- 1 | import recursiveStaircaseDP from '../recursiveStaircaseDP'; 2 | 3 | describe('recursiveStaircaseDP', () => { 4 | it('should calculate number of variants using Dynamic Programming solution', () => { 5 | expect(recursiveStaircaseDP(-1)).toBe(0); 6 | expect(recursiveStaircaseDP(0)).toBe(0); 7 | expect(recursiveStaircaseDP(1)).toBe(1); 8 | expect(recursiveStaircaseDP(2)).toBe(2); 9 | expect(recursiveStaircaseDP(3)).toBe(3); 10 | expect(recursiveStaircaseDP(4)).toBe(5); 11 | expect(recursiveStaircaseDP(5)).toBe(8); 12 | expect(recursiveStaircaseDP(6)).toBe(13); 13 | expect(recursiveStaircaseDP(7)).toBe(21); 14 | expect(recursiveStaircaseDP(8)).toBe(34); 15 | expect(recursiveStaircaseDP(9)).toBe(55); 16 | expect(recursiveStaircaseDP(10)).toBe(89); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseIT.test.js: -------------------------------------------------------------------------------- 1 | import recursiveStaircaseIT from '../recursiveStaircaseIT'; 2 | 3 | describe('recursiveStaircaseIT', () => { 4 | it('should calculate number of variants using Iterative solution', () => { 5 | expect(recursiveStaircaseIT(-1)).toBe(0); 6 | expect(recursiveStaircaseIT(0)).toBe(0); 7 | expect(recursiveStaircaseIT(1)).toBe(1); 8 | expect(recursiveStaircaseIT(2)).toBe(2); 9 | expect(recursiveStaircaseIT(3)).toBe(3); 10 | expect(recursiveStaircaseIT(4)).toBe(5); 11 | expect(recursiveStaircaseIT(5)).toBe(8); 12 | expect(recursiveStaircaseIT(6)).toBe(13); 13 | expect(recursiveStaircaseIT(7)).toBe(21); 14 | expect(recursiveStaircaseIT(8)).toBe(34); 15 | expect(recursiveStaircaseIT(9)).toBe(55); 16 | expect(recursiveStaircaseIT(10)).toBe(89); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/__test__/recursiveStaircaseMEM.test.js: -------------------------------------------------------------------------------- 1 | import recursiveStaircaseMEM from '../recursiveStaircaseMEM'; 2 | 3 | describe('recursiveStaircaseMEM', () => { 4 | it('should calculate number of variants using Brute Force with Memoization', () => { 5 | expect(recursiveStaircaseMEM(-1)).toBe(0); 6 | expect(recursiveStaircaseMEM(0)).toBe(0); 7 | expect(recursiveStaircaseMEM(1)).toBe(1); 8 | expect(recursiveStaircaseMEM(2)).toBe(2); 9 | expect(recursiveStaircaseMEM(3)).toBe(3); 10 | expect(recursiveStaircaseMEM(4)).toBe(5); 11 | expect(recursiveStaircaseMEM(5)).toBe(8); 12 | expect(recursiveStaircaseMEM(6)).toBe(13); 13 | expect(recursiveStaircaseMEM(7)).toBe(21); 14 | expect(recursiveStaircaseMEM(8)).toBe(34); 15 | expect(recursiveStaircaseMEM(9)).toBe(55); 16 | expect(recursiveStaircaseMEM(10)).toBe(89); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseBF.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Recursive Staircase Problem (Brute Force Solution). 3 | * 4 | * @param {number} stairsNum - Number of stairs to climb on. 5 | * @return {number} - Number of ways to climb a staircase. 6 | */ 7 | export default function recursiveStaircaseBF(stairsNum) { 8 | if (stairsNum <= 0) { 9 | // There is no way to go down - you climb the stairs only upwards. 10 | // Also if you're standing on the ground floor that you don't need to do any further steps. 11 | return 0; 12 | } 13 | 14 | if (stairsNum === 1) { 15 | // There is only one way to go to the first step. 16 | return 1; 17 | } 18 | 19 | if (stairsNum === 2) { 20 | // There are two ways to get to the second steps: (1 + 1) or (2). 21 | return 2; 22 | } 23 | 24 | // Sum up how many steps we need to take after doing one step up with the number of 25 | // steps we need to take after doing two steps up. 26 | return recursiveStaircaseBF(stairsNum - 1) + recursiveStaircaseBF(stairsNum - 2); 27 | } 28 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseDP.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Recursive Staircase Problem (Dynamic Programming Solution). 3 | * 4 | * @param {number} stairsNum - Number of stairs to climb on. 5 | * @return {number} - Number of ways to climb a staircase. 6 | */ 7 | export default function recursiveStaircaseDP(stairsNum) { 8 | if (stairsNum < 0) { 9 | // There is no way to go down - you climb the stairs only upwards. 10 | return 0; 11 | } 12 | 13 | // Init the steps vector that will hold all possible ways to get to the corresponding step. 14 | const steps = new Array(stairsNum + 1).fill(0); 15 | 16 | // Init the number of ways to get to the 0th, 1st and 2nd steps. 17 | steps[0] = 0; 18 | steps[1] = 1; 19 | steps[2] = 2; 20 | 21 | if (stairsNum <= 2) { 22 | // Return the number of ways to get to the 0th or 1st or 2nd steps. 23 | return steps[stairsNum]; 24 | } 25 | 26 | // Calculate every next step based on two previous ones. 27 | for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) { 28 | steps[currentStep] = steps[currentStep - 1] + steps[currentStep - 2]; 29 | } 30 | 31 | // Return possible ways to get to the requested step. 32 | return steps[stairsNum]; 33 | } 34 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/recursive-staircase/recursiveStaircaseIT.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Recursive Staircase Problem (Iterative Solution). 3 | * 4 | * @param {number} stairsNum - Number of stairs to climb on. 5 | * @return {number} - Number of ways to climb a staircase. 6 | */ 7 | export default function recursiveStaircaseIT(stairsNum) { 8 | if (stairsNum <= 0) { 9 | // There is no way to go down - you climb the stairs only upwards. 10 | // Also you don't need to do anything to stay on the 0th step. 11 | return 0; 12 | } 13 | 14 | // Init the number of ways to get to the 0th, 1st and 2nd steps. 15 | const steps = [1, 2]; 16 | 17 | if (stairsNum <= 2) { 18 | // Return the number of possible ways of how to get to the 1st or 2nd steps. 19 | return steps[stairsNum - 1]; 20 | } 21 | 22 | // Calculate the number of ways to get to the n'th step based on previous ones. 23 | // Comparing to Dynamic Programming solution we don't store info for all the steps but 24 | // rather for two previous ones only. 25 | for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) { 26 | [steps[0], steps[1]] = [steps[1], steps[0] + steps[1]]; 27 | } 28 | 29 | // Return possible ways to get to the requested step. 30 | return steps[1]; 31 | } 32 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/unique-paths/__test__/btUniquePaths.test.js: -------------------------------------------------------------------------------- 1 | import btUniquePaths from '../btUniquePaths'; 2 | 3 | describe('btUniquePaths', () => { 4 | it('should find the number of unique paths on board', () => { 5 | expect(btUniquePaths(3, 2)).toBe(3); 6 | expect(btUniquePaths(7, 3)).toBe(28); 7 | expect(btUniquePaths(3, 7)).toBe(28); 8 | expect(btUniquePaths(10, 10)).toBe(48620); 9 | expect(btUniquePaths(100, 1)).toBe(1); 10 | expect(btUniquePaths(1, 100)).toBe(1); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/unique-paths/__test__/dpUniquePaths.test.js: -------------------------------------------------------------------------------- 1 | import dpUniquePaths from '../dpUniquePaths'; 2 | 3 | describe('dpUniquePaths', () => { 4 | it('should find the number of unique paths on board', () => { 5 | expect(dpUniquePaths(3, 2)).toBe(3); 6 | expect(dpUniquePaths(7, 3)).toBe(28); 7 | expect(dpUniquePaths(3, 7)).toBe(28); 8 | expect(dpUniquePaths(10, 10)).toBe(48620); 9 | expect(dpUniquePaths(100, 1)).toBe(1); 10 | expect(dpUniquePaths(1, 100)).toBe(1); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/unique-paths/__test__/uniquePaths.test.js: -------------------------------------------------------------------------------- 1 | import uniquePaths from '../uniquePaths'; 2 | 3 | describe('uniquePaths', () => { 4 | it('should find the number of unique paths on board', () => { 5 | expect(uniquePaths(3, 2)).toBe(3); 6 | expect(uniquePaths(7, 3)).toBe(28); 7 | expect(uniquePaths(3, 7)).toBe(28); 8 | expect(uniquePaths(10, 10)).toBe(48620); 9 | expect(uniquePaths(100, 1)).toBe(1); 10 | expect(uniquePaths(1, 100)).toBe(1); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/algorithms/uncategorized/unique-paths/uniquePaths.js: -------------------------------------------------------------------------------- 1 | import pascalTriangle from '../../math/pascal-triangle/pascalTriangle'; 2 | 3 | /** 4 | * @param {number} width 5 | * @param {number} height 6 | * @return {number} 7 | */ 8 | export default function uniquePaths(width, height) { 9 | const pascalLine = width + height - 2; 10 | const pascalLinePosition = Math.min(width, height) - 1; 11 | 12 | return pascalTriangle(pascalLine)[pascalLinePosition]; 13 | } 14 | -------------------------------------------------------------------------------- /src/data-structures/disjoint-set/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Система неперетинних множин 2 | 3 | **Система неперетинних множин** це структура даних (також звана структурою даної пошуку перетину або 4 | безліччю пошуку злиття), яка управляє безліччю елементів, розбитих на кілька підмножин, що не перетинаються. 5 | Вона надає близько-константний час виконання операцій (обмежений зворотною функцією Акерманна) за додаванням 6 | нових множин, *злиття існуючих множин і *випередження, чи відносяться елементи до одного і того ж безлічі. 7 | 8 | Застосовується для зберігання компонентів зв'язності в графах, зокрема, алгоритму Фарбала необхідна подібна структура 9 | даних для ефективної реалізації. 10 | 11 | Основні операції: 12 | 13 | - _MakeSet(x)_ - створює одноелементне безліч {x}, 14 | - _Find(x)_ - повертає ідентифікатор множини, що містить елемент x, 15 | - _Union(x,y)_ - об'єднання множин, що містять x та y. 16 | 17 | Після деяких операцій _об'єднання_, деякі множини зібрані разом. 18 | 19 | ## Посилання 20 | 21 | - [СНМ на Wikipedia](https://uk.wikipedia.org/wiki/%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B5%D0%BF%D0%B5%D1%80%D0%B5%D1%82%D0%B8%D0%BD%D0%BD%D0%B8%D1%85_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B8%D0%BD) 22 | - [СНМ на YouTube](https://www.youtube.com/watch?v=5XwRPwLnK6I) 23 | -------------------------------------------------------------------------------- /src/data-structures/doubly-linked-list/DoublyLinkedListNode.js: -------------------------------------------------------------------------------- 1 | export default class DoublyLinkedListNode { 2 | constructor(value, next = null, previous = null) { 3 | this.value = value; 4 | this.next = next; 5 | this.previous = previous; 6 | } 7 | 8 | toString(callback) { 9 | return callback ? callback(this.value) : `${this.value}`; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/data-structures/doubly-linked-list/images/doubly-linked-list.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/doubly-linked-list/images/doubly-linked-list.jpeg -------------------------------------------------------------------------------- /src/data-structures/graph/GraphEdge.js: -------------------------------------------------------------------------------- 1 | export default class GraphEdge { 2 | /** 3 | * @param {GraphVertex} startVertex 4 | * @param {GraphVertex} endVertex 5 | * @param {number} [weight=1] 6 | */ 7 | constructor(startVertex, endVertex, weight = 0) { 8 | this.startVertex = startVertex; 9 | this.endVertex = endVertex; 10 | this.weight = weight; 11 | } 12 | 13 | /** 14 | * @return {string} 15 | */ 16 | getKey() { 17 | const startVertexKey = this.startVertex.getKey(); 18 | const endVertexKey = this.endVertex.getKey(); 19 | 20 | return `${startVertexKey}_${endVertexKey}`; 21 | } 22 | 23 | /** 24 | * @return {GraphEdge} 25 | */ 26 | reverse() { 27 | const tmp = this.startVertex; 28 | this.startVertex = this.endVertex; 29 | this.endVertex = tmp; 30 | 31 | return this; 32 | } 33 | 34 | /** 35 | * @return {string} 36 | */ 37 | toString() { 38 | return this.getKey(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/data-structures/graph/README.fr-FR.md: -------------------------------------------------------------------------------- 1 | # Graph 2 | 3 | En informatique, un **graphe** est une structure de 4 | données abstraite qui implémente les concepts de 5 | graphe orienté et de graphe non-orienté venant 6 | des mathématiques, plus précisément du domaine de 7 | la théorie des graphes. 8 | 9 | La structure de données abstraite de graphe consiste 10 | en un ensemble fini, éventuellement mutable de sommets 11 | ou nœuds ou points, avec un ensemble de paires ordonnées 12 | ou non de tels éléments. Ces paires sont des arêtes, arcs 13 | non orientés, ou lignes pour un graphe non orienté, et 14 | flèches, arêtes orientées , arcs, ou lignes orientées 15 | dans le cas orienté. Les sommets peuvent faire partie 16 | de la structure, ou être des entités extérieures, 17 | représentées par des entiers ou des références. 18 | 19 | ![Graph](./images/graph.jpeg) 20 | 21 | *Made with [okso.app](https://okso.app)* 22 | 23 | ## References 24 | 25 | - [Wikipedia](https://fr.wikipedia.org/wiki/Graphe_(type_abstrait)) 26 | -------------------------------------------------------------------------------- /src/data-structures/graph/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 图 2 | 3 | 在计算机科学中, **图(graph)** 是一种抽象数据类型, 4 | 旨在实现数学中的无向图和有向图概念,特别是图论领域。 5 | 6 | 一个图数据结构是一个(由有限个或者可变数量的)顶点/节点/点和边构成的有限集。 7 | 8 | 如果顶点对之间是无序的,称为无序图,否则称为有序图; 9 | 10 | 如果顶点对之间的边是没有方向的,称为无向图,否则称为有向图; 11 | 12 | 如果顶点对之间的边是有权重的,该图可称为加权图。 13 | 14 | ![Graph](./images/graph.jpeg) 15 | 16 | *Made with [okso.app](https://okso.app)* 17 | 18 | ## 参考 19 | 20 | - [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type)) 21 | - [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 22 | - [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/data-structures/graph/images/graph.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/graph/images/graph.jpeg -------------------------------------------------------------------------------- /src/data-structures/hash-table/README.ja-JP.md: -------------------------------------------------------------------------------- 1 | # ハッシュテーブル 2 | 3 | コンピュータサイエンスにおいて、**ハッシュテーブル**(ハッシュマップ)は*キーを値にマッピング*できる*連想配列*の機能を持ったデータ構造です。ハッシュテーブルは*ハッシュ関数*を使ってバケットやスロットの配列へのインデックスを計算し、そこから目的の値を見つけることができます。 4 | 5 | 理想的には、ハッシュ関数は各キーを一意のバケットに割り当てますが、ほとんどのハッシュテーブルは不完全なハッシュ関数を採用しているため、複数のキーに対して同じインデックスを生成した時にハッシュの衝突が起こります。このような衝突は何らかの方法で対処する必要があります。 6 | 7 | ![Hash Table](./images/hash-table.jpeg) 8 | 9 | チェイン法によるハッシュの衝突の解決例 10 | 11 | ![Hash Collision](./images/collision-resolution.jpeg) 12 | 13 | *Made with [okso.app](https://okso.app)* 14 | 15 | ## 参考 16 | 17 | - [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) 18 | - [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 19 | -------------------------------------------------------------------------------- /src/data-structures/hash-table/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # Hash Table 2 | 3 | _Read this in other languages:_ 4 | [_简体中文_](README.zh-CN.md), 5 | [_Русский_](README.ru-RU.md), 6 | [_日本語_](README.ja-JP.md), 7 | [_Français_](README.fr-FR.md), 8 | [_Português_](README.pt-BR.md) 9 | 10 | 컴퓨팅에서, **해시 테이블**(해시 맵)은 키를 값에 매핑할 수 있는 구조인 *연관 배열*을 구현하는 자료 구조입니다. 해시 테이블은 *해시 함수*를 사용해 원하는 값을 담을 수 있는 버킷 또는 슬롯 배열의 인덱스를 계산합니다. 11 | 12 | 이상적으로, 해시 함수는 각 키들을 고유 버킷에 할당하지만 대부분의 해시 테이블은 불완전한 해시 함수를 사용하기 때문에 해시 함수를 통해 두 개 이상의 키에 대해 동일한 인덱스를 생성하는 해시 충돌이 발생할 수 있습니다. 이러한 해시 충돌은 어떠한 방법으로든 해결되어야 합니다. 13 | 14 | ![Hash Table](./images/hash-table.jpeg) 15 | 16 | *Made with [okso.app](https://okso.app)* 17 | 18 | 다음은 분리 연결법을 통해 해시 충돌을 해결한 예시입니다. 19 | 20 | ![Hash Collision](./images/collision-resolution.jpeg) 21 | 22 | *Made with [okso.app](https://okso.app)* 23 | 24 | ## 참고 25 | 26 | - [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) 27 | - [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 28 | -------------------------------------------------------------------------------- /src/data-structures/hash-table/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Tabela de Hash (Hash Table) 2 | 3 | Na ciência da computação, uma **tabela de hash** (hash table) é uma 4 | estrutura de dados pela qual implementa um tipo de dado abstrado de 5 | *array associativo*, uma estrutura que pode *mapear chaves para valores*. 6 | Uma tabela de hash utiliza uma *função de hash* para calcular um índice 7 | em um _array_ de buckets ou slots, a partir do qual o valor desejado 8 | pode ser encontrado. 9 | 10 | Idealmente, a função de hash irá atribuir a cada chave a um bucket único, 11 | mas a maioria dos designs de tabela de hash emprega uma função de hash 12 | imperfeita, pela qual poderá causar colisões de hashes onde a função de hash 13 | gera o mesmo índice para mais de uma chave. Tais colisões devem ser 14 | acomodados de alguma forma. 15 | 16 | ![Hash Table](./images/hash-table.jpeg) 17 | 18 | Colisão de hash resolvida por encadeamento separado. 19 | 20 | ![Hash Collision](./images/collision-resolution.jpeg) 21 | 22 | *Made with [okso.app](https://okso.app)* 23 | 24 | ## Referências 25 | 26 | - [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) 27 | - [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 28 | -------------------------------------------------------------------------------- /src/data-structures/hash-table/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 哈希表 2 | 3 | 在计算中, 一个 **哈希表(hash table 或hash map)** 是一种实现 *关联数组(associative array)* 4 | 的抽象数据类型, 该结构可以将 *键映射到值*。 5 | 6 | 哈希表使用 *哈希函数/散列函数* 来计算一个值在数组或桶(buckets)中或槽(slots)中对应的索引,可使用该索引找到所需的值。 7 | 8 | 理想情况下,散列函数将为每个键分配给一个唯一的桶(bucket),但是大多数哈希表设计采用不完美的散列函数,这可能会导致"哈希冲突(hash collisions)",也就是散列函数为多个键(key)生成了相同的索引,这种碰撞必须 9 | 以某种方式进行处理。 10 | 11 | 12 | ![Hash Table](./images/hash-table.jpeg) 13 | 14 | *Made with [okso.app](https://okso.app)* 15 | 16 | 通过单独的链接解决哈希冲突 17 | 18 | ![Hash Collision](./images/collision-resolution.jpeg) 19 | 20 | *Made with [okso.app](https://okso.app)* 21 | 22 | ## 参考 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) 25 | - [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 26 | -------------------------------------------------------------------------------- /src/data-structures/hash-table/images/collision-resolution.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/hash-table/images/collision-resolution.jpeg -------------------------------------------------------------------------------- /src/data-structures/hash-table/images/hash-table.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/hash-table/images/hash-table.jpeg -------------------------------------------------------------------------------- /src/data-structures/heap/MaxHeap.js: -------------------------------------------------------------------------------- 1 | import Heap from './Heap'; 2 | 3 | export default class MaxHeap extends Heap { 4 | /** 5 | * Checks if pair of heap elements is in correct order. 6 | * For MinHeap the first element must be always smaller or equal. 7 | * For MaxHeap the first element must be always bigger or equal. 8 | * 9 | * @param {*} firstElement 10 | * @param {*} secondElement 11 | * @return {boolean} 12 | */ 13 | pairIsInCorrectOrder(firstElement, secondElement) { 14 | return this.compare.greaterThanOrEqual(firstElement, secondElement); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/data-structures/heap/MinHeap.js: -------------------------------------------------------------------------------- 1 | import Heap from './Heap'; 2 | 3 | export default class MinHeap extends Heap { 4 | /** 5 | * Checks if pair of heap elements is in correct order. 6 | * For MinHeap the first element must be always smaller or equal. 7 | * For MaxHeap the first element must be always bigger or equal. 8 | * 9 | * @param {*} firstElement 10 | * @param {*} secondElement 11 | * @return {boolean} 12 | */ 13 | pairIsInCorrectOrder(firstElement, secondElement) { 14 | return this.compare.lessThanOrEqual(firstElement, secondElement); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.fr-FR.md: -------------------------------------------------------------------------------- 1 | # Tas (structure de données) 2 | 3 | En informatique, un **tas** est une structure de données arborescente spécialisée qui satisfait la propriété de tas décrite ci-dessous. 4 | 5 | Dans un *tas minimal* (en anglais *min heap*), si `P` est un nœud parent de `C`, alors la clé (la valeur) de `P` est inférieure ou égale à la clé de `C`. 6 | 7 | ![MinHeap](./images/min-heap.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | Dans un *tas maximal* (en anglais *max heap*), la clé de `P` est supérieure ou égale à la clé de `C`. 12 | 13 | ![MaxHeap](./images/max-heap.jpeg) 14 | 15 | ![Array Representation](./images/array-representation.jpeg) 16 | 17 | Le nœud au «sommet» du tas sans parents est appelé le nœud racine. 18 | 19 | ## Références 20 | 21 | - [Wikipedia](https://fr.wikipedia.org/wiki/Tas_(informatique)) 22 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.ja-JP.md: -------------------------------------------------------------------------------- 1 | # ヒープ (データ構造) 2 | 3 | コンピュータサイエンスにおいて、*ヒープ*は特殊な木構造のデータ構造で、後述するヒープの特性を持っています。 4 | 5 | *最小ヒープ*では、もし`P`が`C`の親ノードの場合、`P`のキー(値)は`C`のキーより小さい、または等しくなります。 6 | 7 | ![MinHeap](./images/min-heap.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | *最大ヒープ*では、`P`のキーは`C`のキーより大きい、もしくは等しくなります。 12 | 13 | ![MaxHeap](./images/max-heap.jpeg) 14 | 15 | ![Array Representation](./images/array-representation.jpeg) 16 | 17 | ヒープの「トップ」のノードには親ノードが存在せず、ルートノードと呼ばれます。 18 | 19 | ## 参考 20 | 21 | - [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure)) 22 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # 힙 (자료구조) 2 | 3 | 컴퓨터 과학에서의 **힙**은 아래에 설명된 힙 속성을 만족하는 전문화된 트리 기반 데이터구조입니다. 4 | 5 | *최소 힙*에서 `P`가 `C`의 상위 노드라면 `P`의 키(값)는 `C`의 키보다 작거나 같습니다. 6 | 7 | ![MinHeap](./images/min-heap.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | *최대 힙*에서 `P`의 키는 `C`의 키보다 크거나 같습니다. 12 | 13 | ![MaxHeap](./images/max-heap.jpeg) 14 | 15 | ![Array Representation](./images/array-representation.jpeg) 16 | 17 | 상위 노드가 없는 힙의 "상단"에 있는 노드를 루트 노드라고 합니다. 18 | 19 | ## 참조 20 | 21 | - [Wikipedia]() 22 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | 24 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Heap (estrutura de dados) 2 | 3 | Na ciência da computação, um **heap** é uma estrutura de dados 4 | baseada em uma árvore especializada que satisfaz a propriedade _heap_ descrita abaixo. 5 | 6 | Em um *heap mínimo* (min heap), caso `P` é um nó pai de `C`, então a chave 7 | (o valor) de `P` é menor ou igual a chave de `C`. 8 | 9 | ![MinHeap](./images/min-heap.jpeg) 10 | 11 | *Made with [okso.app](https://okso.app)* 12 | 13 | Em uma *heap máximo* (max heap), a chave de `P` é maior ou igual 14 | a chave de `C`. 15 | 16 | ![MaxHeap](./images/max-heap.jpeg) 17 | 18 | ![Array Representation](./images/array-representation.jpeg) 19 | 20 | O nó no "topo" do _heap_, cujo não possui pais, é chamado de nó raiz. 21 | 22 | ## References 23 | 24 | - [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure)) 25 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 26 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.ru-RU.md: -------------------------------------------------------------------------------- 1 | # Куча (структура данных) 2 | 3 | В компьютерных науках куча — это специализированная структура данных типа дерево, которая удовлетворяет свойству кучи: 4 | если B является узлом-потомком узла A, то ключ(A) ≥ ключ(B). Из этого следует, что элемент с наибольшим ключом всегда 5 | является корневым узлом кучи, поэтому иногда такие кучи называют max-кучами. 6 | 7 | ![MaxHeap](./images/max-heap.jpeg) 8 | 9 | ![Array Representation](./images/array-representation.jpeg) 10 | 11 | Если сравнение перевернуть, то наименьший элемент будет всегда корневым узлом, такие кучи называют min-кучами. 12 | 13 | ![MinHeap](./images/min-heap.jpeg) 14 | 15 | *Made with [okso.app](https://okso.app)* 16 | 17 | Не существует никаких ограничений относительно того, сколько узлов-потомков имеет каждый узел кучи. На практике их 18 | число обычно не более двух. Куча является максимально эффективной реализацией абстрактного типа данных, который 19 | называется очередью с приоритетом. 20 | 21 | Узел на вершине кучи, у которого нет родителей, называется корневым узлом. 22 | 23 | ## Ссылки 24 | 25 | - [Wikipedia](https://ru.wikipedia.org/wiki/Куча_(структура_данных)) 26 | - [YouTube](https://www.youtube.com/watch?v=noQ4SUoqrQA) 27 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.tr-TR.md: -------------------------------------------------------------------------------- 1 | # Heap (data-structure) 2 | 3 | Bilgisayar biliminde, **yığın (heap)** aşağıda açıklanan özellikleri karşılayan ağaç tabanlı(tree-based) özel bir veri yapısıdır. 4 | 5 | *min heap*, Eğer `P`, `C`'nin üst düğümü ise, `P`'nin anahtarı (değeri) `C`'nin anahtarından (değerinden) küçük veya ona eşittir. 6 | 7 | ![MinHeap](./images/min-heap.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | *max heap*, `P`'nin anahtarı `C`'nin anahtarından büyük veya eşittir. 12 | 13 | ![MaxHeap](./images/max-heap.jpeg) 14 | 15 | ![Array Representation](./images/array-representation.jpeg) 16 | 17 | Yığının (Heap) "en üstündeki" ebeveyni olmayan düğüme kök düğüm (root node) denir. 18 | 19 | ## Referanslar 20 | 21 | - [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure)) 22 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 23 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Купа (структура даних) 2 | 3 | У комп'ютерних науках купа - це спеціалізована структура даних на кшталт дерева, яка задовольняє властивості купи: 4 | якщо B є вузлом-нащадком вузла A, то ключ (A) ≥ ключ (B). З цього випливає, що елемент із найбільшим ключем завжди 5 | є кореневим вузлом купи, тому іноді такі купи називають max-купами. 6 | 7 | ![MaxHeap](./images/max-heap.jpeg) 8 | 9 | ![Array Representation](./images/array-representation.jpeg) 10 | 11 | Якщо порівняння перевернути, то найменший елемент завжди буде кореневим вузлом, такі купи називають min-купами. 12 | 13 | ![MinHeap](./images/min-heap.jpeg) 14 | 15 | *Made with [okso.app](https://okso.app)* 16 | 17 | Не існує жодних обмежень щодо того, скільки вузлів-нащадків має кожен вузол купи. На практиці їх 18 | число зазвичай трохи більше двох. Купа є максимально ефективною реалізацією абстрактного типу даних, який 19 | називається чергою із пріоритетом. 20 | 21 | Вузол на вершині купи, який не має батьків, називається кореневим вузлом. 22 | 23 | ## Посилання 24 | 25 | - [Wikipedia](https://uk.wikipedia.org/wiki/%D0%9A%D1%83%D0%BF%D0%B0_(%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85)) 26 | -------------------------------------------------------------------------------- /src/data-structures/heap/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 堆 (数据结构) 2 | 3 | 在计算机科学中, 一个 **堆(heap)** 是一种特殊的基于树的数据结构,它满足下面描述的堆属性。 4 | 5 | 在一个 *最小堆(min heap)* 中, 如果 `P` 是 `C` 的一个父级节点, 那么 `P` 的key(或value)应小于或等于 `C` 的对应值. 6 | 7 | ![M最小堆](./images/min-heap.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | 在一个 *最大堆(max heap)* 中, `P` 的key(或value)大于 `C` 的对应值。 12 | 13 | ![堆](./images/max-heap.jpeg) 14 | 15 | ![Array Representation](./images/array-representation.jpeg) 16 | 17 | 18 | 在堆“顶部”的没有父级节点的节点,被称之为根节点。 19 | 20 | ## 参考 21 | 22 | - [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure)) 23 | - [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) 24 | -------------------------------------------------------------------------------- /src/data-structures/heap/__test__/Heap.test.js: -------------------------------------------------------------------------------- 1 | import Heap from '../Heap'; 2 | 3 | describe('Heap', () => { 4 | it('should not allow to create instance of the Heap directly', () => { 5 | const instantiateHeap = () => { 6 | const heap = new Heap(); 7 | heap.add(5); 8 | }; 9 | 10 | expect(instantiateHeap).toThrow(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/data-structures/heap/images/array-representation.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/heap/images/array-representation.jpeg -------------------------------------------------------------------------------- /src/data-structures/heap/images/max-heap.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/heap/images/max-heap.jpeg -------------------------------------------------------------------------------- /src/data-structures/heap/images/min-heap.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/heap/images/min-heap.jpeg -------------------------------------------------------------------------------- /src/data-structures/linked-list/LinkedListNode.js: -------------------------------------------------------------------------------- 1 | export default class LinkedListNode { 2 | constructor(value, next = null) { 3 | this.value = value; 4 | this.next = next; 5 | } 6 | 7 | toString(callback) { 8 | return callback ? callback(this.value) : `${this.value}`; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/data-structures/linked-list/images/linked-list.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/linked-list/images/linked-list.jpeg -------------------------------------------------------------------------------- /src/data-structures/lru-cache/images/lru-cache.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/lru-cache/images/lru-cache.jpg -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.fr-FR.md: -------------------------------------------------------------------------------- 1 | # File de priorité 2 | 3 | En informatique, une **file de priorité** est un type 4 | de données abstrait qui s'apparente à une file d'attente normale 5 | ou une structure de données empilées, mais où chaque élément est 6 | en plus associé à une "priorité". 7 | Dans une file de priorité, un élément avec une priorité élevée 8 | est servi avant un élément à faible priorité. Si deux éléments ont 9 | la même priorité, ils sont servis selon leur ordre dans la file 10 | d'attente. 11 | 12 | Alors que les files de priorité sont souvent implémentées avec des tas, 13 | elles sont conceptuellement distinctes des tas. Une file de priorité 14 | est un concept abstrait comme "une liste" ou "une carte"; tout comme 15 | une liste peut être implémentée avec une liste chaînée ou un tableau, 16 | une file de priorité peut être implémentée avec un tas ou une variété 17 | d'autres méthodes telles qu'un tableau non ordonné. 18 | 19 | ## Références 20 | 21 | - [Wikipedia](https://fr.wikipedia.org/wiki/File_de_priorit%C3%A9) 22 | - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6) 23 | -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.ja-JP.md: -------------------------------------------------------------------------------- 1 | # 優先度付きキュー 2 | 3 | コンピュータサイエンスにおいて、**優先度付きキュー**は通常のキューやスタックのデータ構造と似た抽象データ型ですが、各要素に「優先度」が関連づけられています。優先度付きキューでは優先度の高い要素が優先度の低い要素よりも先に処理されます。もし2つの要素が同じ優先度だった場合、それらはキュー内の順序に従って処理されます。 4 | 5 | 優先度付きキューは多くの場合ヒープによって実装されていますが、概念的にはヒープとは異なります。優先度付きキューは「リスト」や「マップ」のような抽象的な概念です。リストがリンクリストや配列で実装できるのと同様に、優先度付きキューはヒープや未ソート配列のような様々な方法で実装することができます。 6 | 7 | ## 参考 8 | 9 | - [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue) 10 | - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6) 11 | -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # 우선 순위 큐 2 | 3 | 컴퓨터 과학에서 **우선 순위 큐**는 일반 큐 또는 스택 데이터 구조와 같은 추상 데이터 유형이지만, 여기서 각 요소에는 "우선 순위"가 연결됩니다. 4 | 우선 순위 큐에서는 우선 순위가 높은 요소가 낮은 요소 앞에 제공됩니다. 두 요소가 동일한 우선 순위를 가질 경우 큐의 순서에 따라 제공됩니다. 5 | 6 | 우선 순위 큐는 종종 힙을 사용하여 구현되지만 개념적으로는 힙과 구별됩니다. 우선 순위 대기열은 "리스트(list)" 또는 "맵(map)"과 같은 추상적인 개념입니다; 7 | 리스트가 링크드 리스트나 배열로 구현될 수 있는 것처럼 우선 순위 큐는 힙이나 정렬되지 않은 배열과 같은 다양한 다른 방법으로 구현될 수 있습니다. 8 | 9 | ## 참조 10 | 11 | - [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue) 12 | - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6) 13 | -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Fila de Prioridade (Priority Queue) 2 | 3 | Na ciência da computação, uma **fila de prioridade** é um tipo de estrutura de 4 | dados abastrata que é como uma fila regular (regular queue) ou estrutura de 5 | dados de pilha (stack), mas adicionalmente cada elemento possui uma 6 | "prioridade" associada. 7 | 8 | Em uma fila de prioridade, um elemento com uma prioridade alta é servido 9 | antes de um elemento com baixa prioridade. Caso dois elementos posusam a 10 | mesma prioridade, eles serão servidos de acordo com sua ordem na fila. 11 | 12 | Enquanto as filas de prioridade são frequentemente implementadas com 13 | pilhas (stacks), elas são conceitualmente distintas das pilhas (stacks). 14 | A fila de prioridade é um conceito abstrato como uma "lista" (list) ou 15 | um "mapa" (map); assim como uma lista pode ser implementada com uma 16 | lista encadeada (liked list) ou um array, a fila de prioridade pode ser 17 | implementada com uma pilha (stack) ou com uma variedade de outros métodos, 18 | como um array não ordenado (unordered array). 19 | 20 | ## Referências 21 | 22 | - [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue) 23 | - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6) 24 | -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Черга з пріоритетом 2 | 3 | Черга з пріоритетом (англ. priority queue) - абстрактний тип даних в інформатиці, 4 | для кожного елемента якого можна визначити його пріоритет. 5 | 6 | У черзі з пріоритетами елемент із високим пріоритетом обслуговується раніше 7 | елемент з низьким пріоритетом. Якщо два елементи мають однаковий пріоритет, вони 8 | обслуговуються відповідно до їх порядку в черзі. 9 | 10 | Черга з пріоритетом підтримує дві обов'язкові операції – додати елемент та 11 | витягти максимум (мінімум). 12 | 13 | Хоча пріоритетні черги часто реалізуються у вигляді куп (heaps), вони 14 | концептуально відрізняються від куп. Черга пріоритетів є абстрактною 15 | концепцією на кшталт «списку» чи «карти»; так само, як список може бути реалізований 16 | у вигляді зв'язкового списку або масиву, так і черга з пріоритетом може бути реалізована 17 | у вигляді купи або безліччю інших методів, наприклад, у вигляді невпорядкованого масиву. 18 | 19 | ## Посилання 20 | 21 | - [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A7%D0%B5%D1%80%D0%B3%D0%B0_%D0%B7_%D0%BF%D1%80%D1%96%D0%BE%D1%80%D0%B8%D1%82%D0%B5%D1%82%D0%BE%D0%BC) 22 | -------------------------------------------------------------------------------- /src/data-structures/priority-queue/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 优先队列 2 | 3 | 在计算机科学中, **优先级队列(priority queue)** 是一种抽象数据类型, 它类似于常规的队列或栈, 但每个元素都有与之关联的“优先级”。 4 | 5 | 在优先队列中, 低优先级的元素之前前面应该是高优先级的元素。 如果两个元素具有相同的优先级, 则根据它们在队列中的顺序是它们的出现顺序即可。 6 | 7 | 优先队列虽通常用堆来实现,但它在概念上与堆不同。优先队列是一个抽象概念,就像“列表”或“图”这样的抽象概念一样; 8 | 9 | 正如列表可以用链表或数组实现一样,优先队列可以用堆或各种其他方法实现,例如无序数组。 10 | 11 | 12 | ## 参考 13 | 14 | - [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue) 15 | - [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6) 16 | -------------------------------------------------------------------------------- /src/data-structures/queue/README.ja-JP.md: -------------------------------------------------------------------------------- 1 | # キュー 2 | 3 | コンピュータサイエンスにおいて、**キュー**は特定の種類の抽象データ型またはコレクションです。コレクションの中のエンティティは順番に並べられており、コレクションに対する基本的な(または唯一の)操作は末尾にエンティティを追加するエンキューと、先頭からエンティティを削除するデキューがあります。これにより、キューは先入れ先出し(FIFO)のデータ構造となります。FIFOのデータ構造では、キューに追加された最初の要素が最初に削除されます。これは、新しい要素が追加されたら、その要素を削除するにはそれまでに追加された全ての要素が削除されなければならないという要件と同じです。多くの場合、ピークのような先頭の要素を検査する操作も備えていて、これはデキューせずに先頭の要素の値を返します。キューは線形のデータ構造や、より抽象的なシーケンシャルなコレクションの一例です。 4 | 5 | FIFO(先入れ先出し)のキュー 6 | 7 | ![Queue](./images/queue.jpeg) 8 | 9 | *Made with [okso.app](https://okso.app)* 10 | 11 | ## 参考 12 | 13 | - [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) 14 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 15 | -------------------------------------------------------------------------------- /src/data-structures/queue/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # Queue 2 | 3 | _Read this in other languages:_ 4 | [_简体中文_](README.zh-CN.md), 5 | [_Русский_](README.ru-RU.md), 6 | [_日本語_](README.ja-JP.md), 7 | [_Français_](README.fr-FR.md), 8 | [_Português_](README.pt-BR.md) 9 | 10 | 컴퓨터 공학에서 **큐**는 일종의 추상 데이터 타입이자 컬렉션입니다. 큐 내부의 엔터티들은 순서를 유지하며 컬렉션의 가장 뒷 부분에 엔터티를 추가하는 인큐(enqueue), 컬렉션의 가장 앞에 위치한 엔터티를 제거하는 디큐(dequeue) 작업을 수행합니다. 이것은 큐를 선입선출 자료 구조로 만듭니다. 선입선출 자료 구조에서는, 추가된 첫 번째 요소가 가장 먼저 제거되는 요소가 됩니다. 이는 새로운 요소가 추가되면 이전에 추가되었던 모든 요소들을 제거해야 새로운 요소를 제거할 수 있다는것과 같은 의미입니다. 또한 큐의 가장 앞에 위치한 요소를 반환하기 위한 작업이 입력되면 디큐 작업 없이 해당 요소를 반환합니다. 11 | 12 | 큐는 선형 자료 구조의 예시이며, 더 추상적으로는 순차적인 컬렉션입니다. 13 | 14 | 선입선출 자료 구조인 큐를 나타내면 다음과 같습니다. 15 | 16 | ![Queue](./images/queue.jpeg) 17 | 18 | *Made with [okso.app](https://okso.app)* 19 | 20 | ## 참고 21 | 22 | - [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) 23 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 24 | -------------------------------------------------------------------------------- /src/data-structures/queue/README.ru-RU.md: -------------------------------------------------------------------------------- 1 | # Очередь 2 | 3 | Очередь (англ. queue) - структура данных в информатике, в которой элементы 4 | хранятся в порядке их добавления. Добавление новых элементов(enqueue) 5 | осуществляется в конец списка. А удаление элементов (dequeue) 6 | осуществляется с начала. Таким образом очередь реализует принцип 7 | "первым вошёл - первым вышел" (FIFO). Часто реализуется операция чтения 8 | головного элемента (peek), которая возвращает первый в очереди элемент, 9 | при этом не удаляя его. Очередь является примером линейной структуры 10 | данных или последовательной коллекции. 11 | 12 | Иллюстрация работы с очередью. 13 | 14 | ![Очередь](./images/queue.jpeg) 15 | 16 | *Made with [okso.app](https://okso.app)* 17 | 18 | ## References 19 | 20 | - [Wikipedia](https://ru.wikipedia.org/wiki/%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) 21 | - [YouTube](https://www.youtube.com/watch?v=GRsVMTlBIoE) 22 | -------------------------------------------------------------------------------- /src/data-structures/queue/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Черга 2 | 3 | Черга (англ. queue) – структура даних в інформатиці, в якій елементи 4 | зберігаються у порядку їх додавання. Додавання нових елементів(enqueue) 5 | здійснюється на кінець списку. А видалення елементів (dequeue) 6 | здійснюється із початку. Таким чином черга реалізує принцип 7 | "першим увійшов – першим вийшов" (FIFO). Часто реалізується операція читання 8 | головного елемента (peek), яка повертає перший у черзі елемент, 9 | при цьому не видаляючи його. Черга є прикладом лінійної структури 10 | даних чи послідовної колекції. 11 | 12 | Ілюстрація роботи з чергою. 13 | 14 | ![Черга](./images/queue.jpeg) 15 | 16 | *Made with [okso.app](https://okso.app)* 17 | 18 | ## Список літератури 19 | 20 | - [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A7%D0%B5%D1%80%D0%B3%D0%B0_(%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D0%B4%D0%B0%D0%BD%D0%B8%D1%85)) 21 | - [YouTube](https://www.youtube.com/watch?v=ll4QLNSPn60) 22 | -------------------------------------------------------------------------------- /src/data-structures/queue/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 队列 2 | 3 | 在计算机科学中, 一个 **队列(queue)** 是一种特殊类型的抽象数据类型或集合。集合中的实体按顺序保存。 4 | 5 | 队列基本操作有两种:入队和出队。从队列的后端位置添加实体,称为入队;从队列的前端位置移除实体,称为出队。 6 | 7 | 8 | 队列中元素先进先出 FIFO (first in, first out)的示意 9 | 10 | ![Queue](./images/queue.jpeg) 11 | 12 | *Made with [okso.app](https://okso.app)* 13 | 14 | ## 参考 15 | 16 | - [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) 17 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 18 | -------------------------------------------------------------------------------- /src/data-structures/queue/images/queue.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/queue/images/queue.jpeg -------------------------------------------------------------------------------- /src/data-structures/stack/README.ja-JP.md: -------------------------------------------------------------------------------- 1 | # スタック 2 | 3 | コンピュータサイエンスにおいて、**スタック**は抽象データ型で、2つの主要な操作ができる要素のコレクションです。 4 | 5 | * **プッシュ**はコレクションに要素を追加します。 6 | * **ポップ**は最近追加された要素でまだ削除されていないものを削除します。 7 | 8 | 要素がスタックから外れる順番から、LIFO(後入れ先出し)とも呼ばれます。スタックに変更を加えることなく、先頭の要素を検査するピーク操作を備えることもあります。「スタック」という名前は、物理的な物を上に積み重ねていく様子との類似性に由来しています。一番上の物を取ることは簡単ですが、スタックの下の方にあるものを取るときは先に上にある複数の物を取り除く必要があります。 9 | 10 | プッシュとポップの例 11 | 12 | ![Stack](./images/stack.jpeg) 13 | 14 | *Made with [okso.app](https://okso.app)* 15 | 16 | ## 参考 17 | 18 | - [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 19 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 20 | -------------------------------------------------------------------------------- /src/data-structures/stack/README.ko-KR.md: -------------------------------------------------------------------------------- 1 | # 스택 2 | 3 | _Read this in other languages:_ 4 | [_简体中文_](README.zh-CN.md), 5 | [_Русский_](README.ru-RU.md), 6 | [_日本語_](README.ja-JP.md), 7 | [_Français_](README.fr-FR.md), 8 | [_Português_](README.pt-BR.md) 9 | 10 | 컴퓨터 과학에서, **스택**은 아래의 두가지 연산을 가진 요소들의 집합인 추상 자료형입니다. 11 | 12 | * **push**는 집합에 요소를 추가하는 것이며, 13 | * **pop**은 아직 제거되지 않은 가장 최근에 추가된 요소를 제거하는 연산입니다. 14 | 15 | 요소가 스택에서 나오는 과정은 LIFO (last in, first out)라는 이름으로 확인할 수 있습니다. 추가적으로, peek 연산은 스택을 수정하지 않고 최상단의 요소에 접근할 수 있게 해줍니다. 이런 자료구조의 "스택"이라는 이름은 실제 물건들이 다른 물건들의 위에 쌓이게 되는 것에서 유추되었습니다. 스택의 최상단의 물건은 빼내기 쉽지만 깊이 있는 물건을 빼내려면 다른 물건들을 먼저 빼내야 하는게 필요합니다. 16 | 17 | 다음은 push와 pop 연산을 실행하는 간단한 스택의 실행입니다. 18 | 19 | ![Stack](./images/stack.jpeg) 20 | 21 | *Made with [okso.app](https://okso.app)* 22 | 23 | ## 참조 24 | 25 | - [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 26 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 27 | -------------------------------------------------------------------------------- /src/data-structures/stack/README.pt-BR.md: -------------------------------------------------------------------------------- 1 | # Pilha (Stack) 2 | 3 | Na ciência da computação, uma **pilha** é uma estrutura de dados abstrata 4 | que serve como uma coleção de elementos com duas operações principais: 5 | 6 | * **push**, pela qual adiciona um elemento à coleção, e 7 | * **pop**, pela qual remove o último elemento adicionado. 8 | 9 | A ordem em que os elementos saem de um _stack_ dá origem ao seu 10 | nome alternativo, LIFO (last in, first out). Adicionalmente, uma operação 11 | de espiada (peek) pode dar acesso ao topo sem modificar o _stack_. 12 | O nome "stack" para este tipo de estrutura vem da analogia de 13 | um conjunto de itens físicos empilhados uns sobre os outros, 14 | o que facilita retirar um item do topo da pilha, enquanto para chegar a 15 | um item mais profundo na pilha pode exigir a retirada de 16 | vários outros itens primeiro. 17 | 18 | Representação simples de um tempo de execução de pilha com operações 19 | _push_ e _pop_. 20 | 21 | ![Stack](./images/stack.jpeg) 22 | 23 | *Made with [okso.app](https://okso.app)* 24 | 25 | ## Referências 26 | 27 | - [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 28 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 29 | -------------------------------------------------------------------------------- /src/data-structures/stack/README.ru-RU.md: -------------------------------------------------------------------------------- 1 | # Стек 2 | 3 | Стек (англ. stack — стопка) — абстрактный тип данных, представляющий собой 4 | список элементов, организованных по принципу LIFO (последним пришёл — первым вышел). 5 | 6 | Стек имеет две ключевые операции: 7 | * **добавление (push)** элемента в конец стека, и 8 | * **удаление (pop)**, последнего добавленного элемента. 9 | 10 | Дополнительная операция чтения головного элемента (peek) даёт доступ 11 | к последнему элементу стека без изменения самого стека. 12 | 13 | Чаще всего принцип работы стека сравнивают со стопкой тарелок: чтобы взять вторую 14 | сверху, нужно снять верхнюю. 15 | 16 | Иллюстрация работы со стеком. 17 | 18 | ![Stack](./images/stack.jpeg) 19 | 20 | *Made with [okso.app](https://okso.app)* 21 | 22 | ## Ссылки 23 | 24 | - [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA) 25 | - [YouTube](https://www.youtube.com/watch?v=tH8qi7lej5U) 26 | -------------------------------------------------------------------------------- /src/data-structures/stack/README.uk-UA.md: -------------------------------------------------------------------------------- 1 | # Стек 2 | 3 | Стек (англ. stack - стопка) - абстрактний тип даних, що представляє собою 4 | список елементів, організованих за принципом LIFO (останнім прийшов – першим вийшов). 5 | 6 | Стек має дві ключові операції: 7 | * **додавання (push)** елемента в кінець стеку, та 8 | * **видалення (pop)**, останнього доданого елемента. 9 | 10 | Додаткова операція для читання головного елемента (peek) дає доступ 11 | до останнього елементу стека без зміни самого стека. 12 | 13 | Найчастіше принцип роботи стека порівнюють із стопкою тарілок: щоб узяти другу 14 | зверху потрібно спочатку зняти верхню. 15 | 16 | Ілюстрація роботи зі стеком. 17 | 18 | ![Стек](./images/stack.jpeg) 19 | 20 | *Made with [okso.app](https://okso.app)* 21 | 22 | ## Посилання 23 | 24 | - [Wikipedia](https://uk.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA) 25 | - [YouTube](https://www.youtube.com/watch?v=4jh1e1YCbYc) 26 | -------------------------------------------------------------------------------- /src/data-structures/stack/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 栈 2 | 3 | 在计算机科学中, 一个 **栈(stack)** 是一种抽象数据类型,用作表示元素的集合,具有两种主要操作: 4 | 5 | * **push**, 添加元素到栈的顶端(末尾); 6 | * **pop**, 移除栈最顶端(末尾)的元素. 7 | 8 | 以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。 9 | 10 | 此外,应有一个 `peek` 操作用于访问栈当前顶端(末尾)的元素。 11 | 12 | "栈"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。 13 | 14 | 栈的 push 和 pop 操作的示意 15 | 16 | ![Stack](./images/stack.jpeg) 17 | 18 | *Made with [okso.app](https://okso.app)* 19 | 20 | ## 参考 21 | 22 | - [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) 23 | - [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&) 24 | -------------------------------------------------------------------------------- /src/data-structures/stack/images/stack.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/stack/images/stack.jpeg -------------------------------------------------------------------------------- /src/data-structures/stack/images/stack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/stack/images/stack.jpg -------------------------------------------------------------------------------- /src/data-structures/tree/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 树 2 | 3 | * [二叉搜索树](binary-search-tree) 4 | * [AVL树](avl-tree) 5 | * [红黑树](red-black-tree) 6 | * [线段树](segment-tree) - with min/max/sum range queries examples 7 | * [芬威克树/Fenwick Tree](fenwick-tree) (Binary Indexed Tree) 8 | 9 | 在计算机科学中, **树(tree)** 是一种广泛使用的抽象数据类型(ADT)— 或实现此ADT的数据结构 — 模拟分层树结构, 具有根节点和有父节点的子树,表示为一组链接节点。 10 | 11 | 树可以被(本地地)递归定义为一个(始于一个根节点的)节点集, 每个节点都是一个包含了值的数据结构, 除了值,还有该节点的节点引用列表(子节点)一起。 12 | 树的节点之间没有引用重复的约束。 13 | 14 | 一棵简单的无序树; 在下图中: 15 | 16 | 标记为7的节点具有两个子节点, 标记为2和6; 17 | 一个父节点,标记为2,作为根节点, 在顶部,没有父节点。 18 | 19 | ![Tree](./images/tree.jpeg) 20 | 21 | *Made with [okso.app](https://okso.app)* 22 | 23 | ## 参考 24 | 25 | - [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure)) 26 | - [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8) 27 | -------------------------------------------------------------------------------- /src/data-structures/tree/binary-search-tree/BinarySearchTree.js: -------------------------------------------------------------------------------- 1 | import BinarySearchTreeNode from './BinarySearchTreeNode'; 2 | 3 | export default class BinarySearchTree { 4 | /** 5 | * @param {function} [nodeValueCompareFunction] 6 | */ 7 | constructor(nodeValueCompareFunction) { 8 | this.root = new BinarySearchTreeNode(null, nodeValueCompareFunction); 9 | 10 | // Steal node comparator from the root. 11 | this.nodeComparator = this.root.nodeComparator; 12 | } 13 | 14 | /** 15 | * @param {*} value 16 | * @return {BinarySearchTreeNode} 17 | */ 18 | insert(value) { 19 | return this.root.insert(value); 20 | } 21 | 22 | /** 23 | * @param {*} value 24 | * @return {boolean} 25 | */ 26 | contains(value) { 27 | return this.root.contains(value); 28 | } 29 | 30 | /** 31 | * @param {*} value 32 | * @return {boolean} 33 | */ 34 | remove(value) { 35 | return this.root.remove(value); 36 | } 37 | 38 | /** 39 | * @return {string} 40 | */ 41 | toString() { 42 | return this.root.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/data-structures/tree/binary-search-tree/images/binary-search-tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/tree/binary-search-tree/images/binary-search-tree.jpg -------------------------------------------------------------------------------- /src/data-structures/tree/images/tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/tree/images/tree.jpeg -------------------------------------------------------------------------------- /src/data-structures/trie/README.ko-KO.md: -------------------------------------------------------------------------------- 1 | # Trie 2 | 3 | _Read this in other languages:_ 4 | [_简体中文_](README.zh-CN.md), 5 | [_Русский_](README.ru-RU.md), 6 | [_Português_](README.pt-BR.md), 7 | [_Українська_](README.uk-UA.md), 8 | [_한국어_](README.ko-KO.md) 9 | 10 | 컴퓨터 과학에서 **트라이**는 디지털 트리라고도 불리며 때로는 기수 트리 또는 접두사 트리(접두사로 검색할 수 있기 때문에)라고도 불리며 일종의 검색 트리입니다. 키가 보통 문자열인 동적 집합 또는 연관 배열을 저장하는 데 사용되는 순서가 지정된 트리 데이터 구조입니다. 이진 검색 트리와 달리 트리의 어떤 노드도 해당 노드와 연결된 키를 저장하지 않으며 대신 트리의 위치가 해당 노드와 연결된 키를 정의합니다. 노드의 모든 하위 항목은 해당 노드와 연결된 문자열의 공통 접두사를 가지며 루트는 빈 문자열과 연결됩니다. 값은 모든 노드와 반드시 연결되지는 않습니다. 오히려 값은 나뭇잎과 관심 있는 키에 해당하는 일부 내부 노드에만 연결되는 경향이 있습니다. 접두사 트리의 공간에 최적화된 표현은 콤팩트 접두사 트리를 참조하십시오. 11 | 12 | ![Trie](./images/trie.jpg) 13 | 14 | _Made with [okso.app](https://okso.app)_ 15 | 16 | ## 참조 17 | 18 | - [Wikipedia]() 19 | - [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s) 20 | -------------------------------------------------------------------------------- /src/data-structures/trie/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 字典树 2 | 3 | 在计算机科学中, **字典树(trie,中文又被称为”单词查找树“或 ”键树“)**, 也称为数字树,有时候也被称为基数树或前缀树(因为它们可以通过前缀搜索),它是一种搜索树--一种已排序的数据结构,通常用于存储动态集或键为字符串的关联数组。 4 | 5 | 与二叉搜索树不同, 树上没有节点存储与该节点关联的键; 相反,节点在树上的位置定义了与之关联的键。一个节点的全部后代节点都有一个与该节点关联的通用的字符串前缀, 与根节点关联的是空字符串。 6 | 7 | 值对于字典树中关联的节点来说,不是必需的,相反,值往往和相关的叶子相关,以及与一些键相关的内部节点相关。 8 | 9 | 有关字典树的空间优化示意,请参阅紧凑前缀树 10 | 11 | ![Trie](./images/trie.jpg) 12 | 13 | *Made with [okso.app](https://okso.app)* 14 | 15 | ## 参考 16 | 17 | - [Wikipedia](https://en.wikipedia.org/wiki/Trie) 18 | - [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s) 19 | -------------------------------------------------------------------------------- /src/data-structures/trie/images/trie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trekhleb/javascript-algorithms/e40a67b5d1aaf006622a90e2bda60043f4f66679/src/data-structures/trie/images/trie.jpg -------------------------------------------------------------------------------- /src/playground/README.md: -------------------------------------------------------------------------------- 1 | # Playground 2 | 3 | You may use `playground.js` file to play with data 4 | structures and algorithms. The code from `playground.js` may 5 | be tested in `./__test__/playground.test.js` file. 6 | 7 | To run tests simply run: 8 | 9 | ``` 10 | npm test -- -t 'playground' 11 | ``` 12 | -------------------------------------------------------------------------------- /src/playground/__test__/playground.test.js: -------------------------------------------------------------------------------- 1 | import playground from '../playground'; 2 | 3 | describe('playground', () => { 4 | it('should return correct results', () => { 5 | // Replace the next dummy test with your playground function tests. 6 | expect(playground()).toBe(120); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/playground/playground.js: -------------------------------------------------------------------------------- 1 | // Import any algorithmic dependencies you need for your playground code here. 2 | import factorial from '../algorithms/math/factorial/factorial'; 3 | 4 | // Write your playground code inside the playground() function. 5 | // Test your code from __tests__/playground.test.js 6 | // Launch playground tests by running: npm test -- 'playground' 7 | function playground() { 8 | // Replace the next line with your playground code. 9 | return factorial(5); 10 | } 11 | 12 | export default playground; 13 | --------------------------------------------------------------------------------