diff --git a/.gitignore b/.gitignore index 640c06087a..e128b69788 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules .idea coverage .vscode +.DS_Store diff --git a/README.md b/README.md index 95a10f8e94..c1cd52a1d4 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ with related explanations and links for further reading (including ones to YouTube videos). _Read this in other languages:_ -[简体中文](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-CN.md), -[繁體中文](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-TW.md) +[简体中文](README.zh-CN.md), +[繁體中文](README.zh-TW.md) ## Data Structures @@ -21,91 +21,98 @@ be accessed and modified efficiently. More precisely, a data structure is a coll values, the relationships among them, and the functions or operations that can be applied to the data. -* [Linked List](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/linked-list) -* [Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue) -* [Stack](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack) -* [Hash Table](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table) -* [Heap](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap) -* [Priority Queue](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/priority-queue) -* [Trie](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/trie) -* [Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree) - * [Binary Search Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/binary-search-tree) - * [AVL Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/avl-tree) - * [Red-Black Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/red-black-tree) - * [Segment Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/segment-tree) - with min/max/sum range queries examples - * [Fenwick Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/fenwick-tree) (Binary Indexed Tree) -* [Graph](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/graph) (both directed and undirected) -* [Disjoint Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/disjoint-set) +`B` - Beginner, `A` - Advanced + +* `B` [Linked List](src/data-structures/linked-list) +* `B` [Queue](src/data-structures/queue) +* `B` [Stack](src/data-structures/stack) +* `B` [Hash Table](src/data-structures/hash-table) +* `B` [Heap](src/data-structures/heap) +* `B` [Priority Queue](src/data-structures/priority-queue) +* `A` [Trie](src/data-structures/trie) +* `A` [Tree](src/data-structures/tree) + * `A` [Binary Search Tree](src/data-structures/tree/binary-search-tree) + * `A` [AVL Tree](src/data-structures/tree/avl-tree) + * `A` [Red-Black Tree](src/data-structures/tree/red-black-tree) + * `A` [Segment Tree](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples + * `A` [Fenwick Tree](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree) +* `A` [Graph](src/data-structures/graph) (both directed and undirected) +* `A` [Disjoint Set](src/data-structures/disjoint-set) ## Algorithms An algorithm is an unambiguous specification of how to solve a class of problems. It is a set of rules that precisely define a sequence of operations. +`B` - Beginner, `A` - Advanced + ### Algorithms by Topic * **Math** - * [Factorial](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/factorial) - * [Fibonacci Number](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [Primality Test](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/primality-test) (trial division method) - * [Euclidean Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) - * [Least Common Multiple](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM) - * [Integer Partition](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) - * [Sieve of Eratosthenes](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit - * [Is Power of Two](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms) - * [Liu Hui π Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/liu-hui) - approximate π calculations based on N-gons + * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. + * `B` [Factorial](src/algorithms/math/factorial) + * `B` [Fibonacci Number](src/algorithms/math/fibonacci) + * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) + * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) + * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) + * `A` [Integer Partition](src/algorithms/math/integer-partition) + * `B` [Sieve of Eratosthenes](src/algorithms/math/sieve-of-eratosthenes) - finding all prime numbers up to any given limit + * `B` [Is Power of Two](src/algorithms/math/is-power-of-two) - check if the number is power of two (naive and bitwise algorithms) + * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons * **Sets** - * [Cartesian Product](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/cartesian-product) - product of multiple sets - * [Power Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - all subsets of a set - * [Permutations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (with and without repetitions) - * [Combinations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (with and without repetitions) - * [Fisher–Yates Shuffle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/fisher-yates) - random permutation of a finite sequence - * [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequence) (LCS) - * [Longest Increasing Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) (SCS) - * [Knapsack Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones - * [Maximum Subarray](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - "Brute Force" and "Dynamic Programming" (Kadane's) versions + * `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets + * `A` [Power Set](src/algorithms/sets/power-set) - all subsets of a set + * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) + * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions) + * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence + * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS) + * `A` [Knapsack Problem](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones + * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - "Brute Force" and "Dynamic Programming" (Kadane's) versions * **Strings** - * [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences - * [Hamming Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different - * [Knuth–Morris–Pratt Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/knuth-morris-pratt) - substring search - * [Rabin Karp Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/rabin-karp) - substring search - * [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) + * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences + * `B` [Hamming Distance](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different + * `A` [Knuth–Morris–Pratt Algorithm](src/algorithms/string/knuth-morris-pratt) (KMP Algorithm) - substring search (pattern matching) + * `A` [Z Algorithm](src/algorithms/string/z-algorithm) - substring search (pattern matching) + * `A` [Rabin Karp Algorithm](src/algorithms/string/rabin-karp) - substring search + * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring) + * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) * **Searches** - * [Linear Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/linear-search) - * [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) + * `B` [Linear Search](src/algorithms/search/linear-search) + * `B` [Binary Search](src/algorithms/search/binary-search) * **Sorting** - * [Bubble Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort) - * [Selection Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort) - * [Insertion Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort) - * [Heap Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/heap-sort) - * [Merge Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [Quicksort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations - * [Shellsort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/shell-sort) - * [Counting Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/counting-sort) - * [Radix Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/radix-sort) + * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort) + * `B` [Selection Sort](src/algorithms/sorting/selection-sort) + * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort) + * `B` [Heap Sort](src/algorithms/sorting/heap-sort) + * `B` [Merge Sort](src/algorithms/sorting/merge-sort) + * `B` [Quicksort](src/algorithms/sorting/quick-sort) - in-place and non-in-place implementations + * `B` [Shellsort](src/algorithms/sorting/shell-sort) + * `A` [Counting Sort](src/algorithms/sorting/counting-sort) + * `A` [Radix Sort](src/algorithms/sorting/radix-sort) * **Trees** - * [Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [Breadth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search) (BFS) + * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS) * **Graphs** - * [Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) - * [Breadth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/breadth-first-search) (BFS) - * [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices - * [Bellman-Ford Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices - * [Detect Cycle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) - * [Prim’s Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [Kruskal’s Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [Topological Sorting](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/topological-sorting) - DFS method - * [Articulation Points](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based) - * [Bridges](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bridges) - DFS based algorithm - * [Eulerian Path and Eulerian Circuit](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once - * [Hamiltonian Cycle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once - * [Strongly Connected Components](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm - * [Travelling Salesman Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city + * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS) + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices + * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) + * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method + * `A` [Articulation Points](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based) + * `A` [Bridges](src/algorithms/graph/bridges) - DFS based algorithm + * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once + * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once + * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm + * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **Uncategorized** - * [Tower of Hanoi](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [N-Queens Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [Knight's Tour](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) + * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) ### Algorithms by Paradigm @@ -114,40 +121,41 @@ of algorithms. It is an abstraction higher than the notion of an algorithm, just algorithm is an abstraction higher than a computer program. * **Brute Force** - look at all the possibilities and selects the best solution - * [Maximum Subarray](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [Travelling Salesman Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city + * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) + * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **Greedy** - choose the best option at the current time, without any consideration for the future - * [Unbound Knapsack Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [Dijkstra Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices - * [Prim’s Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [Kruskal’s Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem) + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices + * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph * **Divide and Conquer** - divide the problem into smaller parts and then solve those parts - * [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) - * [Tower of Hanoi](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [Euclidean Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) - * [Permutations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (with and without repetitions) - * [Combinations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (with and without repetitions) - * [Merge Sort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [Quicksort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - * [Tree Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [Graph Depth-First Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) + * `B` [Binary Search](src/algorithms/search/binary-search) + * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) + * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) + * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions) + * `B` [Merge Sort](src/algorithms/sorting/merge-sort) + * `B` [Quicksort](src/algorithms/sorting/quick-sort) + * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) * **Dynamic Programming** - build up a solution using previously found sub-solutions - * [Fibonacci Number](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences - * [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS) - * [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) - * [Longest Increasing subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) - * [0/1 Knapsack Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [Integer Partition](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) - * [Maximum Subarray](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [Bellman-Ford Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices + * `B` [Fibonacci Number](src/algorithms/math/fibonacci) + * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences + * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring) + * `A` [Longest Increasing subsequence](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) + * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem) + * `A` [Integer Partition](src/algorithms/math/integer-partition) + * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices + * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) * **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate next solution you test if it satisfies all conditions, and only then continue generating subsequent solutions. Otherwise, backtrack, and go on a different path of finding a solution. Normally the DFS traversal of state-space is being used. - * [Hamiltonian Cycle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once - * [N-Queens Problem](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [Knight's Tour](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once + * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) + * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) * **Branch & Bound** - remember the lowest-cost solution found at each stage of the backtracking search, and use the cost of the lowest-cost solution found so far as a lower bound on the cost of a least-cost solution to the problem, in order to discard partial solutions with costs larger than the @@ -224,14 +232,14 @@ Below is the list of some of the most used Big O notations and their performance ### Array Sorting Algorithms Complexity -| Name | Best | Average | Worst | Memory | Stable | Comments | -| --------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: | :-------- | -| **Bubble sort** | n | n^2 | n^2 | 1 | Yes | | -| **Insertion sort** | n | n^2 | n^2 | 1 | Yes | | -| **Selection sort** | n^2 | n^2 | n^2 | 1 | No | | -| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | No | | -| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes | | -| **Quick sort** | n log(n) | n log(n) | n^2 | log(n) | No | | -| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))^2 | 1 | No | | -| **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - biggest number in array | -| **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - length of longest key | +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Bubble sort** | n | n2 | n2 | 1 | Yes | | +| **Insertion sort** | n | n2 | n2 | 1 | Yes | | +| **Selection sort** | n2 | n2 | n2 | 1 | No | | +| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | No | | +| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes | | +| **Quick sort** | n log(n) | n log(n) | n2 | log(n) | No | | +| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))2 | 1 | No | | +| **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - biggest number in array | +| **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - length of longest key | diff --git a/README.zh-CN.md b/README.zh-CN.md index 3a9d7635ad..f42e6d98a0 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -9,25 +9,25 @@ _Read this in other languages:_ [_English_](https://github.com/trekhleb/javascript-algorithms/), -[繁體中文](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-TW.md) +[繁體中文](README.zh-TW.md) ## 数据结构 数据结构是在计算机中组织和存储数据的一种特殊方式,它可以高效地访问和修改数据。更确切地说,数据结构是数据值的集合,它们之间的关系、函数或操作可以应用于数据。 -* [链表](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/linked-list) -* [队列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue) -* [栈](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack) -* [哈希表](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table) -* [堆](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap) -* [优先队列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/priority-queue) -* [字典树](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/trie) -* [树](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree) - * [二分查找](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/binary-search-tree) - * [AVL 树](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/avl-tree) - * [红黑树](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/red-black-tree) -* [图](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/graph) (有向图与无向图) -* [并查集](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/disjoint-set) +* [链表](src/data-structures/linked-list) +* [队列](src/data-structures/queue) +* [栈](src/data-structures/stack) +* [哈希表](src/data-structures/hash-table) +* [堆](src/data-structures/heap) +* [优先队列](src/data-structures/priority-queue) +* [字典树](src/data-structures/trie) +* [树](src/data-structures/tree) + * [二分查找](src/data-structures/tree/binary-search-tree) + * [AVL 树](src/data-structures/tree/avl-tree) + * [红黑树](src/data-structures/tree/red-black-tree) +* [图](src/data-structures/graph) (有向图与无向图) +* [并查集](src/data-structures/disjoint-set) ## 算法 @@ -36,61 +36,61 @@ _Read this in other languages:_ ### 算法主题 * **数学** - * [阶乘](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/factorial) - * [斐波那契数](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [素数检测](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/primality-test) (排除法) - * [欧几里得算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - 计算最大公约数(GCD) - * [最小公倍数](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM) - * [整数拆分](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) + * [阶乘](src/algorithms/math/factorial) + * [斐波那契数](src/algorithms/math/fibonacci) + * [素数检测](src/algorithms/math/primality-test) (排除法) + * [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数(GCD) + * [最小公倍数](src/algorithms/math/least-common-multiple) (LCM) + * [整数拆分](src/algorithms/math/integer-partition) * **集合** - * [笛卡尔积](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/cartesian-product) - 多集合结果 - * [幂集](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - 该集合的所有子集 - * [排列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (有/无重复) - * [组合](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (有/无重复) - * [洗牌算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/fisher-yates) - 随机置换有限序列 - * [最长公共子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequence) (LCS) - * [最长递增子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) (SCS) - * [背包问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones - * [最大子数列问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - BF算法 与 动态编程 + * [笛卡尔积](src/algorithms/sets/cartesian-product) - 多集合结果 + * [幂集](src/algorithms/sets/power-set) - 该集合的所有子集 + * [排列](src/algorithms/sets/permutations) (有/无重复) + * [组合](src/algorithms/sets/combinations) (有/无重复) + * [洗牌算法](src/algorithms/sets/fisher-yates) - 随机置换有限序列 + * [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) + * [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) + * [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS) + * [背包问题](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones + * [最大子数列问题](src/algorithms/sets/maximum-subarray) - BF算法 与 动态编程 * **字符串** - * [莱温斯坦距离](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 - * [汉明距离](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - 符号不同的位置数 - * [克努斯-莫里斯-普拉特算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/knuth-morris-pratt) - 子串搜索 - * [字符串快速查找](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/rabin-karp) - 子串搜索 - * [最长公共子串](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) + * [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 + * [汉明距离](src/algorithms/string/hamming-distance) - 符号不同的位置数 + * [克努斯-莫里斯-普拉特算法](src/algorithms/string/knuth-morris-pratt) - 子串搜索 + * [字符串快速查找](src/algorithms/string/rabin-karp) - 子串搜索 + * [最长公共子串](src/algorithms/string/longest-common-substring) * **搜索** - * [二分查找](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) + * [二分查找](src/algorithms/search/binary-search) * **排序** - * [冒泡排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort) - * [选择排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort) - * [插入排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort) - * [堆排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/heap-sort) - * [归并排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [快速排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - * [希尔排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/shell-sort) + * [冒泡排序](src/algorithms/sorting/bubble-sort) + * [选择排序](src/algorithms/sorting/selection-sort) + * [插入排序](src/algorithms/sorting/insertion-sort) + * [堆排序](src/algorithms/sorting/heap-sort) + * [归并排序](src/algorithms/sorting/merge-sort) + * [快速排序](src/algorithms/sorting/quick-sort) + * [希尔排序](src/algorithms/sorting/shell-sort) * **树** - * [深度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [广度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search) (BFS) + * [深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) + * [广度优先搜索](src/algorithms/tree/breadth-first-search) (BFS) * **图** - * [深度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) - * [广度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/breadth-first-search) (BFS) - * [戴克斯特拉算法m](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 - * [贝尔曼-福特算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 - * [判圈算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/detect-cycle) - 对于有向图和无向图(基于DFS和不相交集的版本) - * [普林演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - 寻找加权无向图的最小生成树(MST) - * [克鲁斯克尔演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树(MST) - * [拓撲排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/topological-sorting) - DFS 方法 - * [关节点](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/articulation-points) - Tarjan算法(基于DFS) - * [桥](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bridges) - 基于DFS的算法 - * [欧拉路径与一笔画问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/eulerian-path) - Fleury的算法 - 一次访问每个边缘 - * [哈密顿图](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 - * [强连通分量](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/strongly-connected-components) - Kosaraju算法 - * [旅行推销员问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 + * [深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) + * [广度优先搜索](src/algorithms/graph/breadth-first-search) (BFS) + * [戴克斯特拉算法m](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 + * [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 + * [判圈算法](src/algorithms/graph/detect-cycle) - 对于有向图和无向图(基于DFS和不相交集的版本) + * [普林演算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树(MST) + * [克鲁斯克尔演算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树(MST) + * [拓撲排序](src/algorithms/graph/topological-sorting) - DFS 方法 + * [关节点](src/algorithms/graph/articulation-points) - Tarjan算法(基于DFS) + * [桥](src/algorithms/graph/bridges) - 基于DFS的算法 + * [欧拉路径与一笔画问题](src/algorithms/graph/eulerian-path) - Fleury的算法 - 一次访问每个边缘 + * [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 + * [强连通分量](src/algorithms/graph/strongly-connected-components) - Kosaraju算法 + * [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 * **未分类** - * [汉诺塔](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [八皇后问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [骑士巡逻](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * [汉诺塔](src/algorithms/uncategorized/hanoi-tower) + * [八皇后问题](src/algorithms/uncategorized/n-queens) + * [骑士巡逻](src/algorithms/uncategorized/knight-tour) ### 算法范式 @@ -98,39 +98,39 @@ _Read this in other languages:_ 算法是比计算机程序更高的抽象。 * **BF算法** - 查找所有可能性并选择最佳解决方案 - * [最大子数列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [旅行推销员问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 + * [最大子数列](src/algorithms/sets/maximum-subarray) + * [旅行推销员问题](src/algorithms/graph/travelling-salesman) - 尽可能以最短的路线访问每个城市并返回原始城市 * **贪心法** - 在当前选择最佳选项,不考虑以后情况 - * [背包问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [戴克斯特拉算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 - * [普里姆算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - 寻找加权无向图的最小生成树(MST) - * [克鲁斯卡尔算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树(MST) + * [背包问题](src/algorithms/sets/knapsack-problem) + * [戴克斯特拉算法](src/algorithms/graph/dijkstra) - 找到所有图顶点的最短路径 + * [普里姆算法](src/algorithms/graph/prim) - 寻找加权无向图的最小生成树(MST) + * [克鲁斯卡尔算法](src/algorithms/graph/kruskal) - 寻找加权无向图的最小生成树(MST) * **分治法** - 将问题分成较小的部分,然后解决这些部分 - * [二分查找](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) - * [汉诺塔](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [欧几里得算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - 计算最大公约数(GCD) - * [排列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (有/无重复) - * [组合](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (有/无重复) - * [归并排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [Quicksort](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - * [树深度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [图深度优先搜索](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) + * [二分查找](src/algorithms/search/binary-search) + * [汉诺塔](src/algorithms/uncategorized/hanoi-tower) + * [欧几里得算法](src/algorithms/math/euclidean-algorithm) - 计算最大公约数(GCD) + * [排列](src/algorithms/sets/permutations) (有/无重复) + * [组合](src/algorithms/sets/combinations) (有/无重复) + * [归并排序](src/algorithms/sorting/merge-sort) + * [Quicksort](src/algorithms/sorting/quick-sort) + * [树深度优先搜索](src/algorithms/tree/depth-first-search) (DFS) + * [图深度优先搜索](src/algorithms/graph/depth-first-search) (DFS) * **动态编程** - 使用以前找到的子解决方案构建解决方案 - * [斐波那契数](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [莱温斯坦距离](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 - * [最长公共子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS) - * [最长公共子串](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) - * [最长递增子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [最短公共子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) - * [0-1背包问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [整数拆分](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) - * [最大子数列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [贝尔曼-福特算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 + * [斐波那契数](src/algorithms/math/fibonacci) + * [莱温斯坦距离](src/algorithms/string/levenshtein-distance) - 两个序列之间的最小编辑距离 + * [最长公共子序列](src/algorithms/sets/longest-common-subsequence) (LCS) + * [最长公共子串](src/algorithms/string/longest-common-substring) + * [最长递增子序列](src/algorithms/sets/longest-increasing-subsequence) + * [最短公共子序列](src/algorithms/sets/shortest-common-supersequence) + * [0-1背包问题](src/algorithms/sets/knapsack-problem) + * [整数拆分](src/algorithms/math/integer-partition) + * [最大子数列](src/algorithms/sets/maximum-subarray) + * [贝尔曼-福特算法](src/algorithms/graph/bellman-ford) - 找到所有图顶点的最短路径 * **回溯法** - 类似于 BF算法 试图产生所有可能的解决方案,但每次生成解决方案测试如果它满足所有条件,那么只有继续生成后续解决方案。 否则回溯并继续寻找不同路径的解决方案。 - * [哈密顿图](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 - * [八皇后问题](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [骑士巡逻](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * [哈密顿图](src/algorithms/graph/hamiltonian-cycle) - 恰好访问每个顶点一次 + * [八皇后问题](src/algorithms/uncategorized/n-queens) + * [骑士巡逻](src/algorithms/uncategorized/knight-tour) * **B & B** ## 如何使用本仓库 diff --git a/README.zh-TW.md b/README.zh-TW.md index e295b47994..8804630450 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -8,25 +8,25 @@ _Read this in other languages:_ [_English_](https://github.com/trekhleb/javascript-algorithms/), -[简体中文](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-CN.md) +[简体中文](README.zh-CN.md) ## 資料結構 資料結構是一個電腦用來組織和排序資料的特定方式,透過這樣的方式資料可以有效率地被讀取以及修改。更精確地說,一個資料結構是一個資料值的集合、彼此間的關係,函數或者運作可以應用於資料上。 -* [鏈結串列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/linked-list) -* [貯列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/queue) -* [堆疊](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/stack) -* [雜湊表](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/hash-table) -* [堆](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/heap) -* [優先貯列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/priority-queue) -* [字典樹](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/trie) -* [樹](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree) - * [二元搜尋樹](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/binary-search-tree) - * [AVL樹](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/avl-tree) - * [紅黑樹](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/red-black-tree) -* [圖](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/graph) (有向跟無向皆包含) -* [互斥集](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/disjoint-set) +* [鏈結串列](src/data-structures/linked-list) +* [貯列](src/data-structures/queue) +* [堆疊](src/data-structures/stack) +* [雜湊表](src/data-structures/hash-table) +* [堆](src/data-structures/heap) +* [優先貯列](src/data-structures/priority-queue) +* [字典樹](src/data-structures/trie) +* [樹](src/data-structures/tree) + * [二元搜尋樹](src/data-structures/tree/binary-search-tree) + * [AVL樹](src/data-structures/tree/avl-tree) + * [紅黑樹](src/data-structures/tree/red-black-tree) +* [圖](src/data-structures/graph) (有向跟無向皆包含) +* [互斥集](src/data-structures/disjoint-set) ## 演算法 @@ -35,99 +35,99 @@ _Read this in other languages:_ ### 演算法議題分類 * **數學類** - * [階層](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/factorial) - * [費伯納西數列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [Primality Test](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/primality-test) (排除法) - * [歐幾里得算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - 計算最大公因數 (GCD) - * [最小公倍數](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM) - * [整數拆分](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) + * [階層](src/algorithms/math/factorial) + * [費伯納西數列](src/algorithms/math/fibonacci) + * [Primality Test](src/algorithms/math/primality-test) (排除法) + * [歐幾里得算法](src/algorithms/math/euclidean-algorithm) - 計算最大公因數 (GCD) + * [最小公倍數](src/algorithms/math/least-common-multiple) (LCM) + * [整數拆分](src/algorithms/math/integer-partition) * **集合** - * [笛卡爾積](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/cartesian-product) - 多個集合的乘積 - * [冪集合](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - 所有集合的子集合 - * [排列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (有/無重複) - * [组合](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (有/無重複) - * [洗牌算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/fisher-yates) - 隨機置換一有限序列 - * [最長共同子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequence) (LCS) - * [最長遞增子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) (SCS) - * [背包問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones - * [最大子序列問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - 暴力法以及動態編程的(Kadane's)版本 + * [笛卡爾積](src/algorithms/sets/cartesian-product) - 多個集合的乘積 + * [冪集合](src/algorithms/sets/power-set) - 所有集合的子集合 + * [排列](src/algorithms/sets/permutations) (有/無重複) + * [组合](src/algorithms/sets/combinations) (有/無重複) + * [洗牌算法](src/algorithms/sets/fisher-yates) - 隨機置換一有限序列 + * [最長共同子序列](src/algorithms/sets/longest-common-subsequence) (LCS) + * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence) + * [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) (SCS) + * [背包問題](src/algorithms/sets/knapsack-problem) - "0/1" and "Unbound" ones + * [最大子序列問題](src/algorithms/sets/maximum-subarray) - 暴力法以及動態編程的(Kadane's)版本 * **字串** - * [萊文斯坦距離](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - 兩序列間的最小編輯距離 - * [漢明距離](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different - * [KMP 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/knuth-morris-pratt) - 子字串搜尋 - * [Rabin Karp 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/rabin-karp) - 子字串搜尋 - * [最長共通子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) + * [萊文斯坦距離](src/algorithms/string/levenshtein-distance) - 兩序列間的最小編輯距離 + * [漢明距離](src/algorithms/string/hamming-distance) - number of positions at which the symbols are different + * [KMP 演算法](src/algorithms/string/knuth-morris-pratt) - 子字串搜尋 + * [Rabin Karp 演算法](src/algorithms/string/rabin-karp) - 子字串搜尋 + * [最長共通子序列](src/algorithms/string/longest-common-substring) * **搜尋** - * [二元搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) + * [二元搜尋](src/algorithms/search/binary-search) * **排序** - * [氣泡排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/bubble-sort) - * [選擇排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/selection-sort) - * [插入排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/insertion-sort) - * [堆排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/heap-sort) - * [合併排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [快速排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - * [希爾排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/shell-sort) + * [氣泡排序](src/algorithms/sorting/bubble-sort) + * [選擇排序](src/algorithms/sorting/selection-sort) + * [插入排序](src/algorithms/sorting/insertion-sort) + * [堆排序](src/algorithms/sorting/heap-sort) + * [合併排序](src/algorithms/sorting/merge-sort) + * [快速排序](src/algorithms/sorting/quick-sort) + * [希爾排序](src/algorithms/sorting/shell-sort) * **樹** - * [深度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [廣度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/breadth-first-search) (BFS) + * [深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS) + * [廣度優先搜尋](src/algorithms/tree/breadth-first-search) (BFS) * **圖** - * [深度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) - * [廣度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/breadth-first-search) (BFS) - * [Dijkstra 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑 - * [Bellman-Ford 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - 找到所有圖頂點的最短路徑 - * [Detect Cycle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) - * [Prim’s 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [Kruskal’s 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [拓撲排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/topological-sorting) - DFS method - * [關節點](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based) - * [橋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bridges) - DFS based algorithm - * [尤拉路徑及尤拉環](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once - * [漢彌爾頓環](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once - * [強連通組件](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm - * [旅行推銷員問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city + * [深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS) + * [廣度優先搜尋](src/algorithms/graph/breadth-first-search) (BFS) + * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑 + * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - 找到所有圖頂點的最短路徑 + * [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) + * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * [拓撲排序](src/algorithms/graph/topological-sorting) - DFS method + * [關節點](src/algorithms/graph/articulation-points) - Tarjan's algorithm (DFS based) + * [橋](src/algorithms/graph/bridges) - DFS based algorithm + * [尤拉路徑及尤拉環](src/algorithms/graph/eulerian-path) - Fleury's algorithm - Visit every edge exactly once + * [漢彌爾頓環](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once + * [強連通組件](src/algorithms/graph/strongly-connected-components) - Kosaraju's algorithm + * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **未分類** - * [河內塔](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [N-皇后問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [騎士走棋盤](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * [河內塔](src/algorithms/uncategorized/hanoi-tower) + * [N-皇后問題](src/algorithms/uncategorized/n-queens) + * [騎士走棋盤](src/algorithms/uncategorized/knight-tour) ### 演算法範型 演算法的範型是一個泛用方法或設計一類底層演算法的方式。它是一個比演算法的概念更高階的抽象化,就像是演算法是比電腦程式更高階的抽象化。 * **暴力法** - 尋遍所有的可能解然後選取最好的解 - * [最大子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [旅行推銷員問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city + * [最大子序列](src/algorithms/sets/maximum-subarray) + * [旅行推銷員問題](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **貪婪法** - choose the best option at the current time, without any consideration for the future - * [未定背包問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [Dijkstra 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑 - * [Prim’s 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * [Kruskal’s 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * [未定背包問題](src/algorithms/sets/knapsack-problem) + * [Dijkstra 演算法](src/algorithms/graph/dijkstra) - 找到所有圖頂點的最短路徑 + * [Prim’s 演算法](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph + * [Kruskal’s 演算法](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph * **分治法** - divide the problem into smaller parts and then solve those parts - * [二元搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) - * [河內塔](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/hanoi-tower) - * [歐幾里得演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) - * [排列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/permutations) (有/無重複) - * [组合](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (有/無重複) - * [合併排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/merge-sort) - * [快速排序](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sorting/quick-sort) - * [樹深度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/tree/depth-first-search) (DFS) - * [圖深度優先搜尋](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/depth-first-search) (DFS) + * [二元搜尋](src/algorithms/search/binary-search) + * [河內塔](src/algorithms/uncategorized/hanoi-tower) + * [歐幾里得演算法](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) + * [排列](src/algorithms/sets/permutations) (有/無重複) + * [组合](src/algorithms/sets/combinations) (有/無重複) + * [合併排序](src/algorithms/sorting/merge-sort) + * [快速排序](src/algorithms/sorting/quick-sort) + * [樹深度優先搜尋](src/algorithms/tree/depth-first-search) (DFS) + * [圖深度優先搜尋](src/algorithms/graph/depth-first-search) (DFS) * **動態編程** - build up to a solution using previously found sub-solutions - * [費伯納西數列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fibonacci) - * [萊溫斯坦距離](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences - * [最長共同子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS) - * [最長共同子字串](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) - * [最長遞增子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence) - * [最短共同子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) - * [0/1背包問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/knapsack-problem) - * [整數拆分](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/integer-partition) - * [最大子序列](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/maximum-subarray) - * [Bellman-Ford 演算法](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices + * [費伯納西數列](src/algorithms/math/fibonacci) + * [萊溫斯坦距離](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences + * [最長共同子序列](src/algorithms/sets/longest-common-subsequnce) (LCS) + * [最長共同子字串](src/algorithms/string/longest-common-substring) + * [最長遞增子序列](src/algorithms/sets/longest-increasing-subsequence) + * [最短共同子序列](src/algorithms/sets/shortest-common-supersequence) + * [0/1背包問題](src/algorithms/sets/knapsack-problem) + * [整數拆分](src/algorithms/math/integer-partition) + * [最大子序列](src/algorithms/sets/maximum-subarray) + * [Bellman-Ford 演算法](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices * **回溯法** - 用類似暴力法來嘗試產生所有可能解,但每次只在能滿足所有測試條件,且只有繼續產生子序列方案來產生的解決方案。否則回溯並尋找不同路徑的解決方案。 - * [漢彌爾頓迴路](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once - * [N-皇后問題](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/n-queens) - * [騎士走棋盤](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/uncategorized/knight-tour) + * [漢彌爾頓迴路](src/algorithms/graph/hamiltonian-cycle) - Visit every vertex exactly once + * [N-皇后問題](src/algorithms/uncategorized/n-queens) + * [騎士走棋盤](src/algorithms/uncategorized/knight-tour) * **Branch & Bound** ## 如何使用本知識庫 diff --git a/package-lock.json b/package-lock.json index 5b229954fc..e7be343899 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "javascript-algorithms-and-data-structures", - "version": "0.0.3", + "version": "0.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md new file mode 100644 index 0000000000..736cbebf1b --- /dev/null +++ b/src/algorithms/math/bits/README.md @@ -0,0 +1,99 @@ +# Bit Manipulation + +#### Get Bit + +This method shifts `1` over by `bitPosition` bits, creating a +value that looks like `00100`. Then we perform `AND` operation +that clears all bits from the original number except the +`bitPosition` one. Then we compare the result with zero. If +result is zero that would mean that original number has `0` at +position `bitPosition`. + +> See `getBit` function for further details. + +#### Set Bit + +This method shifts `1` over by `bitPosition` bits, creating a +value that looks like `00100`. Then we perform `OR` operation +that sets specific bit into `1` but it does not affect on +other bits of the number. + +> See `setBit` function for further details. + +#### Clear Bit + +This method shifts `1` over by `bitPosition` bits, creating a +value that looks like `00100`. Than it inverts this mask to get +the number that looks like `11011`. Then `AND` operation is +being applied to both the number and the mask. That operation +unsets the bit. + +> See `clearBit` function for further details. + +#### Update Bit + +This method is a combination of "Clear Bit" and "Set Bit" methods. + +> See `updateBit` function for further details. + +#### Multiply By Two + +This method shifts original number by one bit to the left. +Thus all binary number components (powers of two) are being +multiplying by two and thus the number itself is being +multiplied by two. + +``` +Before the shift +Number: 0b0101 = 5 +Powers of two: 0 + 2^2 + 0 + 2^0 + +After the shift +Number: 0b1010 = 10 +Powers of two: 2^3 + 0 + 2^1 + 0 +``` + +> See `multiplyByTwo` function for further details. + +#### Divide By Two + +This method shifts original number by one bit to the right. +Thus all binary number components (powers of two) are being +divided by two and thus the number itself is being +divided by two without remainder. + +``` +Before the shift +Number: 0b0101 = 5 +Powers of two: 0 + 2^2 + 0 + 2^0 + +After the shift +Number: 0b0010 = 2 +Powers of two: 0 + 0 + 2^1 + 0 +``` + +> See `divideByTwo` function for further details. + +#### Switch Sign + +This method make positive numbers to be negative and backwards. +To do so it uses "Twos Complement" approach which does it by +inverting all of the bits of the number and adding 1 to it. + +``` +1101 -3 +1110 -2 +1111 -1 +0000 0 +0001 1 +0010 2 +0011 3 +``` + +> See `switchSign` function for further details. + +## References + +- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html) diff --git a/src/algorithms/math/bits/__test__/clearBit.test.js b/src/algorithms/math/bits/__test__/clearBit.test.js new file mode 100644 index 0000000000..2d758779cd --- /dev/null +++ b/src/algorithms/math/bits/__test__/clearBit.test.js @@ -0,0 +1,15 @@ +import clearBit from '../clearBit'; + +describe('clearBit', () => { + it('should clear bit at specific position', () => { + // 1 = 0b0001 + expect(clearBit(1, 0)).toBe(0); + expect(clearBit(1, 1)).toBe(1); + expect(clearBit(1, 2)).toBe(1); + + // 10 = 0b1010 + expect(clearBit(10, 0)).toBe(10); + expect(clearBit(10, 1)).toBe(8); + expect(clearBit(10, 3)).toBe(2); + }); +}); diff --git a/src/algorithms/math/bits/__test__/divideByTwo.test.js b/src/algorithms/math/bits/__test__/divideByTwo.test.js new file mode 100644 index 0000000000..ec829367ec --- /dev/null +++ b/src/algorithms/math/bits/__test__/divideByTwo.test.js @@ -0,0 +1,12 @@ +import divideByTwo from '../divideByTwo'; + +describe('divideByTwo', () => { + it('should divide numbers by two using bitwise operations', () => { + expect(divideByTwo(0)).toBe(0); + expect(divideByTwo(1)).toBe(0); + expect(divideByTwo(3)).toBe(1); + expect(divideByTwo(10)).toBe(5); + expect(divideByTwo(17)).toBe(8); + expect(divideByTwo(125)).toBe(62); + }); +}); diff --git a/src/algorithms/math/bits/__test__/getBit.test.js b/src/algorithms/math/bits/__test__/getBit.test.js new file mode 100644 index 0000000000..3a7026f2d9 --- /dev/null +++ b/src/algorithms/math/bits/__test__/getBit.test.js @@ -0,0 +1,23 @@ +import getBit from '../getBit'; + +describe('getBit', () => { + it('should get bit at specific position', () => { + // 1 = 0b0001 + expect(getBit(1, 0)).toBe(1); + expect(getBit(1, 1)).toBe(0); + + // 2 = 0b0010 + expect(getBit(2, 0)).toBe(0); + expect(getBit(2, 1)).toBe(1); + + // 3 = 0b0011 + expect(getBit(3, 0)).toBe(1); + expect(getBit(3, 1)).toBe(1); + + // 10 = 0b1010 + expect(getBit(10, 0)).toBe(0); + expect(getBit(10, 1)).toBe(1); + expect(getBit(10, 2)).toBe(0); + expect(getBit(10, 3)).toBe(1); + }); +}); diff --git a/src/algorithms/math/bits/__test__/multiplyByTwo.test.js b/src/algorithms/math/bits/__test__/multiplyByTwo.test.js new file mode 100644 index 0000000000..07934c57ba --- /dev/null +++ b/src/algorithms/math/bits/__test__/multiplyByTwo.test.js @@ -0,0 +1,12 @@ +import multiplyByTwo from '../multiplyByTwo'; + +describe('multiplyByTwo', () => { + it('should multiply numbers by two using bitwise operations', () => { + expect(multiplyByTwo(0)).toBe(0); + expect(multiplyByTwo(1)).toBe(2); + expect(multiplyByTwo(3)).toBe(6); + expect(multiplyByTwo(10)).toBe(20); + expect(multiplyByTwo(17)).toBe(34); + expect(multiplyByTwo(125)).toBe(250); + }); +}); diff --git a/src/algorithms/math/bits/__test__/setBit.test.js b/src/algorithms/math/bits/__test__/setBit.test.js new file mode 100644 index 0000000000..d53d60c746 --- /dev/null +++ b/src/algorithms/math/bits/__test__/setBit.test.js @@ -0,0 +1,15 @@ +import setBit from '../setBit'; + +describe('setBit', () => { + it('should set bit at specific position', () => { + // 1 = 0b0001 + expect(setBit(1, 0)).toBe(1); + expect(setBit(1, 1)).toBe(3); + expect(setBit(1, 2)).toBe(5); + + // 10 = 0b1010 + expect(setBit(10, 0)).toBe(11); + expect(setBit(10, 1)).toBe(10); + expect(setBit(10, 2)).toBe(14); + }); +}); diff --git a/src/algorithms/math/bits/__test__/switchSign.test.js b/src/algorithms/math/bits/__test__/switchSign.test.js new file mode 100644 index 0000000000..af3f36df5e --- /dev/null +++ b/src/algorithms/math/bits/__test__/switchSign.test.js @@ -0,0 +1,13 @@ +import switchSign from '../switchSign'; + +describe('switchSign', () => { + it('should switch the sign of the number using twos complement approach', () => { + expect(switchSign(0)).toBe(0); + expect(switchSign(1)).toBe(-1); + expect(switchSign(-1)).toBe(1); + expect(switchSign(32)).toBe(-32); + expect(switchSign(-32)).toBe(32); + expect(switchSign(23)).toBe(-23); + expect(switchSign(-23)).toBe(23); + }); +}); diff --git a/src/algorithms/math/bits/__test__/updateBit.test.js b/src/algorithms/math/bits/__test__/updateBit.test.js new file mode 100644 index 0000000000..e2ac2db005 --- /dev/null +++ b/src/algorithms/math/bits/__test__/updateBit.test.js @@ -0,0 +1,19 @@ +import updateBit from '../updateBit'; + +describe('updateBit', () => { + it('should update bit at specific position', () => { + // 1 = 0b0001 + expect(updateBit(1, 0, 1)).toBe(1); + expect(updateBit(1, 0, 0)).toBe(0); + expect(updateBit(1, 1, 1)).toBe(3); + expect(updateBit(1, 2, 1)).toBe(5); + + // 10 = 0b1010 + expect(updateBit(10, 0, 1)).toBe(11); + expect(updateBit(10, 0, 0)).toBe(10); + expect(updateBit(10, 1, 1)).toBe(10); + expect(updateBit(10, 1, 0)).toBe(8); + expect(updateBit(10, 2, 1)).toBe(14); + expect(updateBit(10, 2, 0)).toBe(10); + }); +}); diff --git a/src/algorithms/math/bits/clearBit.js b/src/algorithms/math/bits/clearBit.js new file mode 100644 index 0000000000..0329a0476d --- /dev/null +++ b/src/algorithms/math/bits/clearBit.js @@ -0,0 +1,10 @@ +/** + * @param {number} number + * @param {number} bitPosition - zero based. + * @return {number} + */ +export default function clearBit(number, bitPosition) { + const mask = ~(1 << bitPosition); + + return number & mask; +} diff --git a/src/algorithms/math/bits/divideByTwo.js b/src/algorithms/math/bits/divideByTwo.js new file mode 100644 index 0000000000..359bef9d59 --- /dev/null +++ b/src/algorithms/math/bits/divideByTwo.js @@ -0,0 +1,7 @@ +/** + * @param {number} number + * @return {number} + */ +export default function divideByTwo(number) { + return number >> 1; +} diff --git a/src/algorithms/math/bits/getBit.js b/src/algorithms/math/bits/getBit.js new file mode 100644 index 0000000000..a99ce7d53b --- /dev/null +++ b/src/algorithms/math/bits/getBit.js @@ -0,0 +1,8 @@ +/** + * @param {number} number + * @param {number} bitPosition - zero based. + * @return {number} + */ +export default function getBit(number, bitPosition) { + return (number & (1 << bitPosition)) === 0 ? 0 : 1; +} diff --git a/src/algorithms/math/bits/multiplyByTwo.js b/src/algorithms/math/bits/multiplyByTwo.js new file mode 100644 index 0000000000..3e52544d29 --- /dev/null +++ b/src/algorithms/math/bits/multiplyByTwo.js @@ -0,0 +1,7 @@ +/** + * @param {number} number + * @return {number} + */ +export default function multiplyByTwo(number) { + return number << 1; +} diff --git a/src/algorithms/math/bits/setBit.js b/src/algorithms/math/bits/setBit.js new file mode 100644 index 0000000000..c574ac692e --- /dev/null +++ b/src/algorithms/math/bits/setBit.js @@ -0,0 +1,8 @@ +/** + * @param {number} number + * @param {number} bitPosition - zero based. + * @return {number} + */ +export default function setBit(number, bitPosition) { + return number | (1 << bitPosition); +} diff --git a/src/algorithms/math/bits/switchSign.js b/src/algorithms/math/bits/switchSign.js new file mode 100644 index 0000000000..e38ec487ef --- /dev/null +++ b/src/algorithms/math/bits/switchSign.js @@ -0,0 +1,8 @@ +/** + * Switch the sign of the number using "Twos Complement" approach. + * @param {number} number + * @return {number} + */ +export default function switchSign(number) { + return ~number + 1; +} diff --git a/src/algorithms/math/bits/updateBit.js b/src/algorithms/math/bits/updateBit.js new file mode 100644 index 0000000000..f56834a3ea --- /dev/null +++ b/src/algorithms/math/bits/updateBit.js @@ -0,0 +1,16 @@ +/** + * @param {number} number + * @param {number} bitPosition - zero based. + * @param {number} bitValue - 0 or 1. + * @return {number} + */ +export default function updateBit(number, bitPosition, bitValue) { + // Normalized bit value. + const bitValueNormalized = bitValue ? 1 : 0; + + // Init clear mask. + const clearMask = ~(1 << bitPosition); + + // Clear bit value and then set it up to required value. + return (number & clearMask) | (bitValueNormalized << bitPosition); +} diff --git a/src/algorithms/math/factorial/__test__/factorialRecursive.test.js b/src/algorithms/math/factorial/__test__/factorialRecursive.test.js new file mode 100644 index 0000000000..9029faee0a --- /dev/null +++ b/src/algorithms/math/factorial/__test__/factorialRecursive.test.js @@ -0,0 +1,11 @@ +import factorialRecursive from '../factorialRecursive'; + +describe('factorialRecursive', () => { + it('should calculate factorial', () => { + expect(factorialRecursive(0)).toBe(1); + expect(factorialRecursive(1)).toBe(1); + expect(factorialRecursive(5)).toBe(120); + expect(factorialRecursive(8)).toBe(40320); + expect(factorialRecursive(10)).toBe(3628800); + }); +}); diff --git a/src/algorithms/math/factorial/factorialRecursive.js b/src/algorithms/math/factorial/factorialRecursive.js new file mode 100644 index 0000000000..e2b4aec6c9 --- /dev/null +++ b/src/algorithms/math/factorial/factorialRecursive.js @@ -0,0 +1,7 @@ +/** + * @param {number} number + * @return {number} + */ +export default function factorialRecursive(number) { + return number > 1 ? number * factorialRecursive(number - 1) : 1; +} diff --git a/src/algorithms/math/fibonacci/fibonacci.js b/src/algorithms/math/fibonacci/fibonacci.js index 3230dfddd6..4caa1d9bd6 100644 --- a/src/algorithms/math/fibonacci/fibonacci.js +++ b/src/algorithms/math/fibonacci/fibonacci.js @@ -18,7 +18,7 @@ export default function fibonacci(n) { while (iterationsCounter) { currentValue += previousValue; - previousValue = (currentValue - previousValue); + previousValue = currentValue - previousValue; fibSequence.push(currentValue); diff --git a/src/algorithms/math/fibonacci/fibonacciNth.js b/src/algorithms/math/fibonacci/fibonacciNth.js index 76bbbe871d..729224470a 100644 --- a/src/algorithms/math/fibonacci/fibonacciNth.js +++ b/src/algorithms/math/fibonacci/fibonacciNth.js @@ -16,7 +16,7 @@ export default function fibonacciNth(n) { while (iterationsCounter) { currentValue += previousValue; - previousValue = (currentValue - previousValue); + previousValue = currentValue - previousValue; iterationsCounter -= 1; } diff --git a/src/algorithms/math/integer-partition/integerPartition.js b/src/algorithms/math/integer-partition/integerPartition.js index 283d9a400e..02cb31f69f 100644 --- a/src/algorithms/math/integer-partition/integerPartition.js +++ b/src/algorithms/math/integer-partition/integerPartition.js @@ -17,9 +17,10 @@ export default function integerPartition(number) { partitionMatrix[0][numberIndex] = 0; } - // Let's fill the first row. It represents the number of way of how we can form - // number zero out of numbers 0, 1, 2, ... Obviously there is only one way we could - // form number 0 and it is with number 0 itself. + // Let's fill the first column. It represents the number of ways we can form + // number zero out of numbers 0, 0 and 1, 0 and 1 and 2, 0 and 1 and 2 and 3, ... + // Obviously there is only one way we could form number 0 + // and it is with number 0 itself. for (let summandIndex = 0; summandIndex <= number; summandIndex += 1) { partitionMatrix[summandIndex][0] = 1; } @@ -33,9 +34,17 @@ export default function integerPartition(number) { // any new ways of forming the number. Thus we may just copy the number from row above. partitionMatrix[summandIndex][numberIndex] = partitionMatrix[summandIndex - 1][numberIndex]; } else { - // The number of combinations would equal to number of combinations of forming the same - // number but WITHOUT current summand number plus number of combinations of forming the - // previous number but WITH current summand. + /* + * The number of combinations would equal to number of combinations of forming the same + * number but WITHOUT current summand number PLUS number of combinations of forming the + * number but WITH current summand. + * + * Example: + * Number of ways to form 5 using summands {0, 1, 2} would equal the SUM of: + * - number of ways to form 5 using summands {0, 1} (we've excluded summand 2) + * - number of ways to form 3 (because 5 - 2 = 3) using summands {0, 1, 2} + * (we've included summand 2) + */ const combosWithoutSummand = partitionMatrix[summandIndex - 1][numberIndex]; const combosWithSummand = partitionMatrix[summandIndex][numberIndex - summandIndex]; diff --git a/src/algorithms/sets/combinations/combineWithRepetitions.js b/src/algorithms/sets/combinations/combineWithRepetitions.js index 0d2ef3c167..8a743289f3 100644 --- a/src/algorithms/sets/combinations/combineWithRepetitions.js +++ b/src/algorithms/sets/combinations/combineWithRepetitions.js @@ -1,38 +1,28 @@ /** - * @param {*[]} combinationOptions - * @param {number} combinationLength + * @param {*[]} comboOptions + * @param {number} comboLength * @return {*[]} */ - -export default function combineWithRepetitions(combinationOptions, combinationLength) { - // If combination length equal to 0 then return empty combination. - if (combinationLength === 0) { - return [[]]; - } - - // If combination options are empty then return "no-combinations" array. - if (combinationOptions.length === 0) { - return []; +export default function combineWithRepetitions(comboOptions, comboLength) { + if (comboLength === 1) { + return comboOptions.map(comboOption => [comboOption]); } // Init combinations array. const combos = []; - // Find all shorter combinations and attach head to each of those. - const headCombo = [combinationOptions[0]]; - const shorterCombos = combineWithRepetitions(combinationOptions, combinationLength - 1); - - for (let combinationIndex = 0; combinationIndex < shorterCombos.length; combinationIndex += 1) { - const combo = headCombo.concat(shorterCombos[combinationIndex]); - combos.push(combo); - } + // Eliminate characters one by one and concatenate them to + // combinations of smaller lengths. + comboOptions.forEach((currentOption, optionIndex) => { + const smallerCombos = combineWithRepetitions( + comboOptions.slice(optionIndex), + comboLength - 1, + ); - // Let's shift head to the right and calculate all the rest combinations. - const combinationsWithoutHead = combineWithRepetitions( - combinationOptions.slice(1), - combinationLength, - ); + smallerCombos.forEach((smallerCombo) => { + combos.push([currentOption].concat(smallerCombo)); + }); + }); - // Join all combinations and return them. - return combos.concat(combinationsWithoutHead); + return combos; } diff --git a/src/algorithms/sets/combinations/combineWithoutRepetitions.js b/src/algorithms/sets/combinations/combineWithoutRepetitions.js index a8217fc5e5..56c1e8fe48 100644 --- a/src/algorithms/sets/combinations/combineWithoutRepetitions.js +++ b/src/algorithms/sets/combinations/combineWithoutRepetitions.js @@ -1,68 +1,28 @@ -/* - @see: https://stackoverflow.com/a/127898/7794070 - - Lets say your array of letters looks like this: "ABCDEFGH". - You have three indices (i, j, k) indicating which letters you - are going to use for the current word, You start with: - - A B C D E F G H - ^ ^ ^ - i j k - - First you vary k, so the next step looks like that: - - A B C D E F G H - ^ ^ ^ - i j k - - If you reached the end you go on and vary j and then k again. - - A B C D E F G H - ^ ^ ^ - i j k - - A B C D E F G H - ^ ^ ^ - i j k - - Once you j reached G you start also to vary i. - - A B C D E F G H - ^ ^ ^ - i j k - - A B C D E F G H - ^ ^ ^ - i j k - ... - */ - /** - * @param {*[]} combinationOptions - * @param {number} combinationLength + * @param {*[]} comboOptions + * @param {number} comboLength * @return {*[]} */ -export default function combineWithoutRepetitions(combinationOptions, combinationLength) { - // If combination length is just 1 then return combinationOptions. - if (combinationLength === 1) { - return combinationOptions.map(option => [option]); +export default function combineWithoutRepetitions(comboOptions, comboLength) { + if (comboLength === 1) { + return comboOptions.map(comboOption => [comboOption]); } // Init combinations array. - const combinations = []; - - for (let i = 0; i <= (combinationOptions.length - combinationLength); i += 1) { - const smallerCombinations = combineWithoutRepetitions( - combinationOptions.slice(i + 1), - combinationLength - 1, + const combos = []; + + // Eliminate characters one by one and concatenate them to + // combinations of smaller lengths. + comboOptions.forEach((currentOption, optionIndex) => { + const smallerCombos = combineWithoutRepetitions( + comboOptions.slice(optionIndex + 1), + comboLength - 1, ); - for (let j = 0; j < smallerCombinations.length; j += 1) { - const combination = [combinationOptions[i]].concat(smallerCombinations[j]); - combinations.push(combination); - } - } + smallerCombos.forEach((smallerCombo) => { + combos.push([currentOption].concat(smallerCombo)); + }); + }); - // Return all calculated combinations. - return combinations; + return combos; } diff --git a/src/algorithms/sets/knapsack-problem/Knapsack.js b/src/algorithms/sets/knapsack-problem/Knapsack.js index d23e12e0fb..9085895702 100644 --- a/src/algorithms/sets/knapsack-problem/Knapsack.js +++ b/src/algorithms/sets/knapsack-problem/Knapsack.js @@ -165,10 +165,17 @@ export default class Knapsack { const availableWeight = this.weightLimit - this.totalWeight; const maxPossibleItemsCount = Math.floor(availableWeight / currentItem.weight); - if (maxPossibleItemsCount) { + if (maxPossibleItemsCount > currentItem.itemsInStock) { + // If we have more items in stock then it is allowed to add + // let's add the maximum allowed number of them. + currentItem.quantity = currentItem.itemsInStock; + } else if (maxPossibleItemsCount) { + // In case if we don't have specified number of items in stock + // let's add only items we have in stock. currentItem.quantity = maxPossibleItemsCount; - this.selectedItems.push(currentItem); } + + this.selectedItems.push(currentItem); } } } diff --git a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js index 9569908f45..d322445a72 100644 --- a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js +++ b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js @@ -96,6 +96,31 @@ describe('Knapsack', () => { new KnapsackItem({ value: 20, weight: 2 }), // v/w ratio is 10 ]; + const maxKnapsackWeight = 15; + + const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight); + + knapsack.solveUnboundedKnapsackProblem(); + + expect(knapsack.totalValue).toBe(84 + 20 + 12 + 10 + 5); + expect(knapsack.totalWeight).toBe(15); + expect(knapsack.selectedItems.length).toBe(5); + expect(knapsack.selectedItems[0].toString()).toBe('v84 w7 x 1'); + expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 1'); + expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 1'); + expect(knapsack.selectedItems[3].toString()).toBe('v12 w3 x 1'); + expect(knapsack.selectedItems[4].toString()).toBe('v5 w2 x 1'); + }); + + it('should solve unbound knapsack problem with items in stock', () => { + const possibleKnapsackItems = [ + new KnapsackItem({ value: 84, weight: 7, itemsInStock: 3 }), // v/w ratio is 12 + new KnapsackItem({ value: 5, weight: 2, itemsInStock: 2 }), // v/w ratio is 2.5 + new KnapsackItem({ value: 12, weight: 3, itemsInStock: 1 }), // v/w ratio is 4 + new KnapsackItem({ value: 10, weight: 1, itemsInStock: 6 }), // v/w ratio is 10 + new KnapsackItem({ value: 20, weight: 2, itemsInStock: 8 }), // v/w ratio is 10 + ]; + const maxKnapsackWeight = 17; const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight); @@ -109,4 +134,29 @@ describe('Knapsack', () => { expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 1'); expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 1'); }); + + it('should solve unbound knapsack problem with items in stock and max weight more than sum of all items', () => { + const possibleKnapsackItems = [ + new KnapsackItem({ value: 84, weight: 7, itemsInStock: 3 }), // v/w ratio is 12 + new KnapsackItem({ value: 5, weight: 2, itemsInStock: 2 }), // v/w ratio is 2.5 + new KnapsackItem({ value: 12, weight: 3, itemsInStock: 1 }), // v/w ratio is 4 + new KnapsackItem({ value: 10, weight: 1, itemsInStock: 6 }), // v/w ratio is 10 + new KnapsackItem({ value: 20, weight: 2, itemsInStock: 8 }), // v/w ratio is 10 + ]; + + const maxKnapsackWeight = 60; + + const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight); + + knapsack.solveUnboundedKnapsackProblem(); + + expect(knapsack.totalValue).toBe((3 * 84) + (2 * 5) + (1 * 12) + (6 * 10) + (8 * 20)); + expect(knapsack.totalWeight).toBe((3 * 7) + (2 * 2) + (1 * 3) + (6 * 1) + (8 * 2)); + expect(knapsack.selectedItems.length).toBe(5); + expect(knapsack.selectedItems[0].toString()).toBe('v84 w7 x 3'); + expect(knapsack.selectedItems[1].toString()).toBe('v20 w2 x 8'); + expect(knapsack.selectedItems[2].toString()).toBe('v10 w1 x 6'); + expect(knapsack.selectedItems[3].toString()).toBe('v12 w3 x 1'); + expect(knapsack.selectedItems[4].toString()).toBe('v5 w2 x 2'); + }); }); diff --git a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js index 2984b7c9e3..0d53def1ae 100644 --- a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js +++ b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js @@ -2,9 +2,6 @@ import permutateWithRepetitions from '../permutateWithRepetitions'; describe('permutateWithRepetitions', () => { it('should permutate string with repetition', () => { - const permutations0 = permutateWithRepetitions([]); - expect(permutations0).toEqual([]); - const permutations1 = permutateWithRepetitions(['A']); expect(permutations1).toEqual([ ['A'], diff --git a/src/algorithms/sets/permutations/permutateWithRepetitions.js b/src/algorithms/sets/permutations/permutateWithRepetitions.js index 25d6fcafa4..90502d29f6 100644 --- a/src/algorithms/sets/permutations/permutateWithRepetitions.js +++ b/src/algorithms/sets/permutations/permutateWithRepetitions.js @@ -1,42 +1,30 @@ /** * @param {*[]} permutationOptions + * @param {number} permutationLength * @return {*[]} */ -export default function permutateWithRepetitions(permutationOptions) { - // There is no permutations for empty array. - if (!permutationOptions || permutationOptions.length === 0) { - return []; +export default function permutateWithRepetitions( + permutationOptions, + permutationLength = permutationOptions.length, +) { + if (permutationLength === 1) { + return permutationOptions.map(permutationOption => [permutationOption]); } - // There is only one permutation for the 1-element array. - if (permutationOptions.length === 1) { - return [permutationOptions]; - } - - // Let's create initial set of permutations. - let previousPermutations = permutationOptions.map(option => [option]); - let currentPermutations = []; - let permutationSize = 1; - - // While the size of each permutation is less then or equal to options length... - while (permutationSize < permutationOptions.length) { - // Reset all current permutations. - currentPermutations = []; + // Init permutations array. + const permutations = []; - for (let permIndex = 0; permIndex < previousPermutations.length; permIndex += 1) { - for (let optionIndex = 0; optionIndex < permutationOptions.length; optionIndex += 1) { - let currentPermutation = previousPermutations[permIndex]; - currentPermutation = currentPermutation.concat([permutationOptions[optionIndex]]); - currentPermutations.push(currentPermutation); - } - } + // Go through all options and join it to the smaller permutations. + permutationOptions.forEach((currentOption) => { + const smallerPermutations = permutateWithRepetitions( + permutationOptions, + permutationLength - 1, + ); - // Make current permutations to be the previous ones. - previousPermutations = currentPermutations.slice(0); - - // Increase permutation size counter. - permutationSize += 1; - } + smallerPermutations.forEach((smallerPermutation) => { + permutations.push([currentOption].concat(smallerPermutation)); + }); + }); - return currentPermutations; + return permutations; } diff --git a/src/algorithms/sorting/bubble-sort/README.md b/src/algorithms/sorting/bubble-sort/README.md index 4861dc2e41..aed7169615 100644 --- a/src/algorithms/sorting/bubble-sort/README.md +++ b/src/algorithms/sorting/bubble-sort/README.md @@ -9,6 +9,12 @@ are needed, which indicates that the list is sorted. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Bubble sort** | n | n2 | n2 | 1 | Yes | | + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Bubble_sort) diff --git a/src/algorithms/sorting/counting-sort/README.md b/src/algorithms/sorting/counting-sort/README.md index 261efe521a..098961a0e0 100644 --- a/src/algorithms/sorting/counting-sort/README.md +++ b/src/algorithms/sorting/counting-sort/README.md @@ -54,6 +54,12 @@ zero. ![Counting Sort](https://1.bp.blogspot.com/-xPqylngqASY/WLGq3p9n9vI/AAAAAAAAAHM/JHdtXAkJY8wYzDMBXxqarjmhpPhM0u8MACLcB/s1600/ResultArrayCS.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - biggest number in array | + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Counting_sort) diff --git a/src/algorithms/sorting/heap-sort/README.md b/src/algorithms/sorting/heap-sort/README.md index 7504875dfa..6ccc50b3b0 100644 --- a/src/algorithms/sorting/heap-sort/README.md +++ b/src/algorithms/sorting/heap-sort/README.md @@ -13,6 +13,12 @@ rather than a linear-time search to find the maximum. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | No | | + ## References [Wikipedia](https://en.wikipedia.org/wiki/Heapsort) diff --git a/src/algorithms/sorting/insertion-sort/README.md b/src/algorithms/sorting/insertion-sort/README.md index a31804d4f3..cd3a74ef34 100644 --- a/src/algorithms/sorting/insertion-sort/README.md +++ b/src/algorithms/sorting/insertion-sort/README.md @@ -10,6 +10,12 @@ sort. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/0/0f/Insertion-sort-example-300px.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Insertion sort** | n | n2 | n2 | 1 | Yes | | + ## References [Wikipedia](https://en.wikipedia.org/wiki/Insertion_sort) diff --git a/src/algorithms/sorting/merge-sort/README.md b/src/algorithms/sorting/merge-sort/README.md index 372cc2ac6b..f4ed837a22 100644 --- a/src/algorithms/sorting/merge-sort/README.md +++ b/src/algorithms/sorting/merge-sort/README.md @@ -22,6 +22,12 @@ emulate merge sort (top-down). ![Merge Sort](https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes | | + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Merge_sort) diff --git a/src/algorithms/sorting/quick-sort/README.md b/src/algorithms/sorting/quick-sort/README.md index 3021e6e2da..683a7f3f71 100644 --- a/src/algorithms/sorting/quick-sort/README.md +++ b/src/algorithms/sorting/quick-sort/README.md @@ -23,6 +23,12 @@ The horizontal lines are pivot values. ![Quicksort](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Quick sort** | n log(n) | n log(n) | n2 | log(n) | No | | + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Quicksort) diff --git a/src/algorithms/sorting/radix-sort/README.md b/src/algorithms/sorting/radix-sort/README.md index 01471cb3fa..1d1fab1852 100644 --- a/src/algorithms/sorting/radix-sort/README.md +++ b/src/algorithms/sorting/radix-sort/README.md @@ -25,6 +25,12 @@ comparison-based sorts (and worse if keys are much longer than `log n`). ![Radix Sort](https://www.researchgate.net/publication/291086231/figure/fig1/AS:614214452404240@1523451545568/Simplistic-illustration-of-the-steps-performed-in-a-radix-sort-In-this-example-the.png) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - length of longest key | + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Radix_sort) diff --git a/src/algorithms/sorting/selection-sort/README.md b/src/algorithms/sorting/selection-sort/README.md index 7a16f205ea..6a708d2579 100644 --- a/src/algorithms/sorting/selection-sort/README.md +++ b/src/algorithms/sorting/selection-sort/README.md @@ -13,6 +13,12 @@ memory is limited. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/9/94/Selection-Sort-Animation.gif) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Selection sort** | n2 | n2 | n2 | 1 | No | | + ## References [Wikipedia](https://en.wikipedia.org/wiki/Selection_sort) diff --git a/src/algorithms/sorting/shell-sort/README.md b/src/algorithms/sorting/shell-sort/README.md index 9d202c55e9..5030333f79 100644 --- a/src/algorithms/sorting/shell-sort/README.md +++ b/src/algorithms/sorting/shell-sort/README.md @@ -42,6 +42,12 @@ Shell sort uses insertion sort to sort the array. ![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort.jpg) +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))2 | 1 | No | | + ## References * [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm) diff --git a/src/algorithms/string/levenshtein-distance/README.md b/src/algorithms/string/levenshtein-distance/README.md index 00019e87fd..cc5b5e9d7f 100644 --- a/src/algorithms/string/levenshtein-distance/README.md +++ b/src/algorithms/string/levenshtein-distance/README.md @@ -40,7 +40,76 @@ three edits: 2. sitt**e**n → sitt**i**n (substitution of "i" for "e") 3. sittin → sittin**g** (insertion of "g" at the end). +## Applications + +This has a wide range of applications, for instance, spell checkers, correction +systems for optical character recognition, fuzzy string searching, and software +to assist natural language translation based on translation memory. + +## Dynamic Programming Approach Explanation + +Let’s take a simple example of finding minimum edit distance between +strings `ME` and `MY`. Intuitively you already know that minimum edit distance +here is `1` operation and this operation. And it is a replacing `E` with `Y`. But +let’s try to formalize it in a form of the algorithm in order to be able to +do more complex examples like transforming `Saturday` into `Sunday`. + +To apply the mathematical formula mentioned above to `ME → MY` transformation +we need to know minimum edit distances of `ME → M`, `M → MY` and `M → M` transformations +in prior. Then we will need to pick the minimum one and add _one_ operation to +transform last letters `E → Y`. So minimum edit distance of `ME → MY` transformation +is being calculated based on three previously possible transformations. + +To explain this further let’s draw the following matrix: + +![Levenshtein Matrix](https://cdn-images-1.medium.com/max/1600/1*2d46ug_PL5LfeqztckoYGw.jpeg) + +- Cell `(0:1)` contains red number 1. It means that we need 1 operation to +transform `M` to an empty string. And it is by deleting `M`. This is why this number is red. +- Cell `(0:2)` contains red number 2. It means that we need 2 operations +to transform `ME` to an empty string. And it is by deleting `E` and `M`. +- Cell `(1:0)` contains green number 1. It means that we need 1 operation +to transform an empty string to `M`. And it is by inserting `M`. This is why this number is green. +- Cell `(2:0)` contains green number 2. It means that we need 2 operations +to transform an empty string to `MY`. And it is by inserting `Y` and `M`. +- Cell `(1:1)` contains number 0. It means that it costs nothing +to transform `M` into `M`. +- Cell `(1:2)` contains red number 1. It means that we need 1 operation +to transform `ME` to `M`. And it is be deleting `E`. +- And so on... + +This looks easy for such small matrix as ours (it is only `3x3`). But here you +may find basic concepts that may be applied to calculate all those numbers for +bigger matrices (let’s say `9x7` one, for `Saturday → Sunday` transformation). + +According to the formula you only need three adjacent cells `(i-1:j)`, `(i-1:j-1)`, and `(i:j-1)` to +calculate the number for current cell `(i:j)`. All we need to do is to find the +minimum of those three cells and then add `1` in case if we have different +letters in `i`'s row and `j`'s column. + +You may clearly see the recursive nature of the problem. + +![Levenshtein Matrix](https://cdn-images-1.medium.com/max/2000/1*JdHQ5TeKiDlE-iKK1s_2vw.jpeg) + +Let's draw a decision graph for this problem. + +![Minimum Edit Distance Decision Graph](https://cdn-images-1.medium.com/max/1600/1*SGwYUpXH9H1xUeTvJk0e7Q.jpeg) + +You may see a number of overlapping sub-problems on the picture that are marked +with red. Also there is no way to reduce the number of operations and make it +less then a minimum of those three adjacent cells from the formula. + +Also you may notice that each cell number in the matrix is being calculated +based on previous ones. Thus the tabulation technique (filling the cache in +bottom-up direction) is being applied here. + +Applying this principles further we may solve more complicated cases like +with `Saturday → Sunday` transformation. + +![Levenshtein distance](https://cdn-images-1.medium.com/max/1600/1*fPEHiImYLKxSTUhrGbYq3g.jpeg) + ## References - [Wikipedia](https://en.wikipedia.org/wiki/Levenshtein_distance) - [YouTube](https://www.youtube.com/watch?v=We3YDTzNXEk&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [ITNext](https://itnext.io/dynamic-programming-vs-divide-and-conquer-2fea680becbe) diff --git a/src/algorithms/string/regular-expression-matching/README.md b/src/algorithms/string/regular-expression-matching/README.md new file mode 100644 index 0000000000..e04c071e40 --- /dev/null +++ b/src/algorithms/string/regular-expression-matching/README.md @@ -0,0 +1,73 @@ +# Regular Expression Matching + +Given an input string `s` and a pattern `p`, implement regular +expression matching with support for `.` and `*`. + +- `.` Matches any single character. +- `*` Matches zero or more of the preceding element. + +The matching should cover the **entire** input string (not partial). + +**Note** + +- `s` could be empty and contains only lowercase letters `a-z`. +- `p` could be empty and contains only lowercase letters `a-z`, and characters like `.` or `*`. + +## Examples + +**Example #1** + +Input: +``` +s = 'aa' +p = 'a' +``` + +Output: `false` + +Explanation: `a` does not match the entire string `aa`. + +**Example #2** + +Input: +``` +s = 'aa' +p = 'a*' +``` + +Output: `true` + +Explanation: `*` means zero or more of the preceding element, `a`. +Therefore, by repeating `a` once, it becomes `aa`. + +**Example #3** + +Input: + +``` +s = 'ab' +p = '.*' +``` + +Output: `true` + +Explanation: `.*` means "zero or more (`*`) of any character (`.`)". + +**Example #4** + +Input: + +``` +s = 'aab' +p = 'c*a*b' +``` + +Output: `true` + +Explanation: `c` can be repeated 0 times, `a` can be repeated +1 time. Therefore it matches `aab`. + +## References + +- [YouTube](https://www.youtube.com/watch?v=l3hda49XcDE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=71&t=0s) +- [LeetCode](https://leetcode.com/problems/regular-expression-matching/description/) diff --git a/src/algorithms/string/regular-expression-matching/__test__/regularExpressionMatching.test.js b/src/algorithms/string/regular-expression-matching/__test__/regularExpressionMatching.test.js new file mode 100644 index 0000000000..b1e676a68e --- /dev/null +++ b/src/algorithms/string/regular-expression-matching/__test__/regularExpressionMatching.test.js @@ -0,0 +1,34 @@ +import regularExpressionMatching from '../regularExpressionMatching'; + +describe('regularExpressionMatching', () => { + it('should match regular expressions in a string', () => { + expect(regularExpressionMatching('', '')).toBeTruthy(); + expect(regularExpressionMatching('a', 'a')).toBeTruthy(); + expect(regularExpressionMatching('aa', 'aa')).toBeTruthy(); + expect(regularExpressionMatching('aab', 'aab')).toBeTruthy(); + expect(regularExpressionMatching('aab', 'aa.')).toBeTruthy(); + expect(regularExpressionMatching('aab', '.a.')).toBeTruthy(); + expect(regularExpressionMatching('aab', '...')).toBeTruthy(); + expect(regularExpressionMatching('a', 'a*')).toBeTruthy(); + expect(regularExpressionMatching('aaa', 'a*')).toBeTruthy(); + expect(regularExpressionMatching('aaab', 'a*b')).toBeTruthy(); + expect(regularExpressionMatching('aaabb', 'a*b*')).toBeTruthy(); + expect(regularExpressionMatching('aaabb', 'a*b*c*')).toBeTruthy(); + expect(regularExpressionMatching('', 'a*')).toBeTruthy(); + expect(regularExpressionMatching('xaabyc', 'xa*b.c')).toBeTruthy(); + expect(regularExpressionMatching('aab', 'c*a*b*')).toBeTruthy(); + expect(regularExpressionMatching('mississippi', 'mis*is*.p*.')).toBeTruthy(); + expect(regularExpressionMatching('ab', '.*')).toBeTruthy(); + + expect(regularExpressionMatching('', 'a')).toBeFalsy(); + expect(regularExpressionMatching('a', '')).toBeFalsy(); + expect(regularExpressionMatching('aab', 'aa')).toBeFalsy(); + expect(regularExpressionMatching('aab', 'baa')).toBeFalsy(); + expect(regularExpressionMatching('aabc', '...')).toBeFalsy(); + expect(regularExpressionMatching('aaabbdd', 'a*b*c*')).toBeFalsy(); + expect(regularExpressionMatching('mississippi', 'mis*is*p*.')).toBeFalsy(); + expect(regularExpressionMatching('ab', 'a*')).toBeFalsy(); + expect(regularExpressionMatching('abba', 'a*b*.c')).toBeFalsy(); + expect(regularExpressionMatching('abba', '.*c')).toBeFalsy(); + }); +}); diff --git a/src/algorithms/string/regular-expression-matching/regularExpressionMatching.js b/src/algorithms/string/regular-expression-matching/regularExpressionMatching.js new file mode 100644 index 0000000000..07ca0e2beb --- /dev/null +++ b/src/algorithms/string/regular-expression-matching/regularExpressionMatching.js @@ -0,0 +1,135 @@ +const ZERO_OR_MORE_CHARS = '*'; +const ANY_CHAR = '.'; + +/** + * Dynamic programming approach. + * + * @param {string} string + * @param {string} pattern + * @return {boolean} + */ +export default function regularExpressionMatching(string, pattern) { + /* + * Let's initiate dynamic programming matrix for this string and pattern. + * We will have pattern characters on top (as columns) and string characters + * will be placed to the left of the table (as rows). + * + * Example: + * + * a * b . b + * - - - - - - + * a - - - - - - + * a - - - - - - + * b - - - - - - + * y - - - - - - + * b - - - - - - + */ + const matchMatrix = Array(string.length + 1).fill(null).map(() => { + return Array(pattern.length + 1).fill(null); + }); + + // Let's fill the top-left cell with true. This would mean that empty + // string '' matches to empty pattern ''. + matchMatrix[0][0] = true; + + // Let's fill the first row of the matrix with false. That would mean that + // empty string can't match any non-empty pattern. + // + // Example: + // string: '' + // pattern: 'a.z' + // + // The one exception here is patterns like a*b* that matches the empty string. + for (let columnIndex = 1; columnIndex <= pattern.length; columnIndex += 1) { + const patternIndex = columnIndex - 1; + + if (pattern[patternIndex] === ZERO_OR_MORE_CHARS) { + matchMatrix[0][columnIndex] = matchMatrix[0][columnIndex - 2]; + } else { + matchMatrix[0][columnIndex] = false; + } + } + + // Let's fill the first column with false. That would mean that empty pattern + // can't match any non-empty string. + // + // Example: + // string: 'ab' + // pattern: '' + for (let rowIndex = 1; rowIndex <= string.length; rowIndex += 1) { + matchMatrix[rowIndex][0] = false; + } + + // Not let's go through every letter of the pattern and every letter of + // the string and compare them one by one. + for (let rowIndex = 1; rowIndex <= string.length; rowIndex += 1) { + for (let columnIndex = 1; columnIndex <= pattern.length; columnIndex += 1) { + // Take into account that fact that matrix contain one extra column and row. + const stringIndex = rowIndex - 1; + const patternIndex = columnIndex - 1; + + if (pattern[patternIndex] === ZERO_OR_MORE_CHARS) { + /* + * In case if current pattern character is special '*' character we have + * two options: + * + * 1. Since * char allows it previous char to not be presented in a string we + * need to check if string matches the pattern without '*' char and without the + * char that goes before '*'. That would mean to go two positions left on the + * same row. + * + * 2. Since * char allows it previous char to be presented in a string many times we + * need to check if char before * is the same as current string char. If they are the + * same that would mean that current string matches the current pattern in case if + * the string WITHOUT current char matches the same pattern. This would mean to go + * one position up in the same row. + */ + if (matchMatrix[rowIndex][columnIndex - 2] === true) { + matchMatrix[rowIndex][columnIndex] = true; + } else if ( + ( + pattern[patternIndex - 1] === string[stringIndex] || + pattern[patternIndex - 1] === ANY_CHAR + ) && + matchMatrix[rowIndex - 1][columnIndex] === true + ) { + matchMatrix[rowIndex][columnIndex] = true; + } else { + matchMatrix[rowIndex][columnIndex] = false; + } + } else if ( + pattern[patternIndex] === string[stringIndex] || + pattern[patternIndex] === ANY_CHAR + ) { + /* + * In case if current pattern char is the same as current string char + * or it may be any character (in case if pattern contains '.' char) + * we need to check if there was a match for the pattern and for the + * string by WITHOUT current char. This would mean that we may copy + * left-top diagonal value. + * + * Example: + * + * a b + * a 1 - + * b - 1 + */ + matchMatrix[rowIndex][columnIndex] = matchMatrix[rowIndex - 1][columnIndex - 1]; + } else { + /* + * In case if pattern char and string char are different we may + * treat this case as "no-match". + * + * Example: + * + * a b + * a - - + * c - 0 + */ + matchMatrix[rowIndex][columnIndex] = false; + } + } + } + + return matchMatrix[string.length][pattern.length]; +} diff --git a/src/algorithms/string/z-algorithm/README.md b/src/algorithms/string/z-algorithm/README.md new file mode 100644 index 0000000000..0f12bc7333 --- /dev/null +++ b/src/algorithms/string/z-algorithm/README.md @@ -0,0 +1,62 @@ +# Z Algorithm + +The Z-algorithm finds occurrences of a "word" `W` +within a main "text string" `T` in linear time `O(|W| + |T|)`. + +Given a string `S` of length `n`, the algorithm produces +an array, `Z` where `Z[i]` represents the longest substring +starting from `S[i]` which is also a prefix of `S`. Finding +`Z` for the string obtained by concatenating the word, `W` +with a nonce character, say `$` followed by the text, `T`, +helps with pattern matching, for if there is some index `i` +such that `Z[i]` equals the pattern length, then the pattern +must be present at that point. + +While the `Z` array can be computed with two nested loops in `O(|W| * |T|)` time, the +following strategy shows how to obtain it in linear time, based +on the idea that as we iterate over the letters in the string +(index `i` from `1` to `n - 1`), we maintain an interval `[L, R]` +which is the interval with maximum `R` such that `1 ≤ L ≤ i ≤ R` +and `S[L...R]` is a prefix that is also a substring (if no such +interval exists, just let `L = R =  - 1`). For `i = 1`, we can +simply compute `L` and `R` by comparing `S[0...]` to `S[1...]`. + +**Example of Z array** + +``` +Index 0 1 2 3 4 5 6 7 8 9 10 11 +Text a a b c a a b x a a a z +Z values X 1 0 0 3 1 0 0 2 2 1 0 +``` + +Other examples + +``` +str = a a a a a a +Z[] = x 5 4 3 2 1 +``` + +``` +str = a a b a a c d +Z[] = x 1 0 2 1 0 0 +``` + +``` +str = a b a b a b a b +Z[] = x 0 6 0 4 0 2 0 +``` + +**Example of Z box** + +![z-box](https://ivanyu.me/wp-content/uploads/2014/09/zalg1.png) + +## Complexity + +- **Time:** `O(|W| + |T|)` +- **Space:** `O(|W|)` + +## References + +- [GeeksForGeeks](https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/) +- [YouTube](https://www.youtube.com/watch?v=CpZh4eF8QBw&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=70) +- [Z Algorithm by Ivan Yurchenko](https://ivanyu.me/blog/2013/10/15/z-algorithm/) diff --git a/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js b/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js new file mode 100644 index 0000000000..9ef1e3f4b4 --- /dev/null +++ b/src/algorithms/string/z-algorithm/__test__/zAlgorithm.test.js @@ -0,0 +1,16 @@ +import zAlgorithm from '../zAlgorithm'; + +describe('zAlgorithm', () => { + it('should find word positions in given text', () => { + expect(zAlgorithm('abcbcglx', 'abca')).toEqual([]); + expect(zAlgorithm('abca', 'abca')).toEqual([0]); + expect(zAlgorithm('abca', 'abcadfd')).toEqual([]); + expect(zAlgorithm('abcbcglabcx', 'abc')).toEqual([0, 7]); + expect(zAlgorithm('abcbcglx', 'bcgl')).toEqual([3]); + expect(zAlgorithm('abcbcglx', 'cglx')).toEqual([4]); + expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabcy')).toEqual([15]); + expect(zAlgorithm('abcxabcdabxabcdabcdabcy', 'abcdabca')).toEqual([]); + expect(zAlgorithm('abcxabcdabxaabcdabcabcdabcdabcy', 'abcdabca')).toEqual([12]); + expect(zAlgorithm('abcxabcdabxaabaabaaaabcdabcdabcy', 'aabaabaaa')).toEqual([11]); + }); +}); diff --git a/src/algorithms/string/z-algorithm/zAlgorithm.js b/src/algorithms/string/z-algorithm/zAlgorithm.js new file mode 100644 index 0000000000..1c532f5f8f --- /dev/null +++ b/src/algorithms/string/z-algorithm/zAlgorithm.js @@ -0,0 +1,132 @@ +// The string separator that is being used for "word" and "text" concatenation. +const SEPARATOR = '$'; + +/** + * @param {string} zString + * @return {number[]} + */ +function buildZArray(zString) { + // Initiate zArray and fill it with zeros. + const zArray = new Array(zString.length).fill(null).map(() => 0); + + // Z box boundaries. + let zBoxLeftIndex = 0; + let zBoxRightIndex = 0; + + // Position of current zBox character that is also a position of + // the same character in prefix. + // For example: + // Z string: ab$xxabxx + // Indices: 012345678 + // Prefix: ab....... + // Z box: .....ab.. + // Z box shift for 'a' would be 0 (0-position in prefix and 0-position in Z box) + // Z box shift for 'b' would be 1 (1-position in prefix and 1-position in Z box) + let zBoxShift = 0; + + // Go through all characters of the zString. + for (let charIndex = 1; charIndex < zString.length; charIndex += 1) { + if (charIndex > zBoxRightIndex) { + // We're OUTSIDE of Z box. In other words this is a case when we're + // starting from Z box of size 1. + + // In this case let's make current character to be a Z box of length 1. + zBoxLeftIndex = charIndex; + zBoxRightIndex = charIndex; + + // Now let's go and check current and the following characters to see if + // they are the same as a prefix. By doing this we will also expand our + // Z box. For example if starting from current position we will find 3 + // more characters that are equal to the ones in the prefix we will expand + // right Z box boundary by 3. + while ( + zBoxRightIndex < zString.length && + zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex] + ) { + // Expanding Z box right boundary. + zBoxRightIndex += 1; + } + + // Now we may calculate how many characters starting from current position + // are are the same as the prefix. We may calculate it by difference between + // right and left Z box boundaries. + zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex; + + // Move right Z box boundary left by one position just because we've used + // [zBoxRightIndex - zBoxLeftIndex] index calculation above. + zBoxRightIndex -= 1; + } else { + // We're INSIDE of Z box. + + // Calculate corresponding Z box shift. Because we want to copy the values + // from zArray that have been calculated before. + zBoxShift = charIndex - zBoxLeftIndex; + + // Check if the value that has been already calculated before + // leaves us inside of Z box or it goes beyond the checkbox + // right boundary. + if (zArray[zBoxShift] < (zBoxRightIndex - charIndex) + 1) { + // If calculated value don't force us to go outside Z box + // then we're safe and we may simply use previously calculated value. + zArray[charIndex] = zArray[zBoxShift]; + } else { + // In case if previously calculated values forces us to go outside of Z box + // we can't safely copy previously calculated zArray value. It is because + // we are sure that there is no further prefix matches outside of Z box. + // Thus such values must be re-calculated and reduced to certain point. + + // To do so we need to shift left boundary of Z box to current position. + zBoxLeftIndex = charIndex; + + // And start comparing characters one by one as we normally do for the case + // when we are outside of checkbox. + while ( + zBoxRightIndex < zString.length && + zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex] + ) { + zBoxRightIndex += 1; + } + + zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex; + + zBoxRightIndex -= 1; + } + } + } + + // Return generated zArray. + return zArray; +} + +/** + * @param {string} text + * @param {string} word + * @return {number[]} + */ +export default function zAlgorithm(text, word) { + // The list of word's positions in text. Word may be found in the same text + // in several different positions. Thus it is an array. + const wordPositions = []; + + // Concatenate word and string. Word will be a prefix to a string. + const zString = `${word}${SEPARATOR}${text}`; + + // Generate Z-array for concatenated string. + const zArray = buildZArray(zString); + + // Based on Z-array properties each cell will tell us the length of the match between + // the string prefix and current sub-text. Thus we're may find all positions in zArray + // with the number that equals to the length of the word (zString prefix) and based on + // that positions we'll be able to calculate word positions in text. + for (let charIndex = 1; charIndex < zArray.length; charIndex += 1) { + if (zArray[charIndex] === word.length) { + // Since we did concatenation to form zString we need to subtract prefix + // and separator lengths. + const wordPosition = charIndex - word.length - SEPARATOR.length; + wordPositions.push(wordPosition); + } + } + + // Return the list of word positions. + return wordPositions; +} diff --git a/src/data-structures/disjoint-set/DisjointSet.js b/src/data-structures/disjoint-set/DisjointSet.js index 2952f0a1b8..2fe3c25c3c 100644 --- a/src/data-structures/disjoint-set/DisjointSet.js +++ b/src/data-structures/disjoint-set/DisjointSet.js @@ -70,7 +70,7 @@ export default class DisjointSet { // If rootB's tree is bigger then make rootB to be a new root. rootB.addChild(rootA); - return rootB.getKey(); + return this; } // If rootA's tree is bigger then make rootA to be a new root. diff --git a/src/data-structures/graph/Graph.js b/src/data-structures/graph/Graph.js index e2ef20b7e0..ae123ca15c 100644 --- a/src/data-structures/graph/Graph.js +++ b/src/data-structures/graph/Graph.js @@ -115,6 +115,11 @@ export default class Graph { */ findEdge(startVertex, endVertex) { const vertex = this.getVertexByKey(startVertex.getKey()); + + if (!vertex) { + return null; + } + return vertex.findEdge(endVertex); } diff --git a/src/data-structures/graph/__test__/Graph.test.js b/src/data-structures/graph/__test__/Graph.test.js index 1c6592ba55..be6e9d7fb2 100644 --- a/src/data-structures/graph/__test__/Graph.test.js +++ b/src/data-structures/graph/__test__/Graph.test.js @@ -87,9 +87,11 @@ describe('Graph', () => { const graphEdgeAB = graph.findEdge(vertexA, vertexB); const graphEdgeBA = graph.findEdge(vertexB, vertexA); - const graphEdgeAC = graph.findEdge(vertexB, vertexC); + const graphEdgeAC = graph.findEdge(vertexA, vertexC); + const graphEdgeCA = graph.findEdge(vertexC, vertexA); expect(graphEdgeAC).toBeNull(); + expect(graphEdgeCA).toBeNull(); expect(graphEdgeAB).toEqual(edgeAB); expect(graphEdgeBA).toEqual(edgeAB); expect(graphEdgeAB.weight).toBe(10); @@ -108,9 +110,11 @@ describe('Graph', () => { const graphEdgeAB = graph.findEdge(vertexA, vertexB); const graphEdgeBA = graph.findEdge(vertexB, vertexA); - const graphEdgeAC = graph.findEdge(vertexB, vertexC); + const graphEdgeAC = graph.findEdge(vertexA, vertexC); + const graphEdgeCA = graph.findEdge(vertexC, vertexA); expect(graphEdgeAC).toBeNull(); + expect(graphEdgeCA).toBeNull(); expect(graphEdgeBA).toBeNull(); expect(graphEdgeAB).toEqual(edgeAB); expect(graphEdgeAB.weight).toBe(10); diff --git a/src/data-structures/tree/BinaryTreeNode.js b/src/data-structures/tree/BinaryTreeNode.js index 71e7ae0d3f..44c9390e41 100644 --- a/src/data-structures/tree/BinaryTreeNode.js +++ b/src/data-structures/tree/BinaryTreeNode.js @@ -69,7 +69,7 @@ export default class BinaryTreeNode { return undefined; } - // Check if grand-parent has more than two children. + // Check if grand-parent has two children. if (!this.parent.parent.left || !this.parent.parent.right) { return undefined; } @@ -85,6 +85,16 @@ export default class BinaryTreeNode { return this.parent.parent.left; } + /** + * @param {*} value + * @return {BinaryTreeNode} + */ + setValue(value) { + this.value = value; + + return this; + } + /** * @param {BinaryTreeNode} node * @return {BinaryTreeNode} @@ -168,6 +178,16 @@ export default class BinaryTreeNode { return false; } + /** + * @param {BinaryTreeNode} sourceNode + * @param {BinaryTreeNode} targetNode + */ + static copyNode(sourceNode, targetNode) { + targetNode.setValue(sourceNode.value); + targetNode.setLeft(sourceNode.left); + targetNode.setRight(sourceNode.right); + } + /** * @return {*[]} */ diff --git a/src/data-structures/tree/README.md b/src/data-structures/tree/README.md index 13445b7fd7..42e69cc68b 100644 --- a/src/data-structures/tree/README.md +++ b/src/data-structures/tree/README.md @@ -1,7 +1,10 @@ # Tree -* [Binary Search Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/binary-search-tree) -* [AVL Tree](https://github.com/trekhleb/javascript-algorithms/tree/master/src/data-structures/tree/avl-tree) +* [Binary Search Tree](binary-search-tree) +* [AVL Tree](avl-tree) +* [Red-Black Tree](red-black-tree) +* [Segment Tree](segment-tree) - with min/max/sum range queries examples +* [Fenwick Tree](fenwick-tree) (Binary Indexed Tree) In computer science, a tree is a widely used abstract data type (ADT) — or data structure implementing this ADT—that diff --git a/src/data-structures/tree/__test__/BinaryTreeNode.test.js b/src/data-structures/tree/__test__/BinaryTreeNode.test.js index 5a38329614..bc2336e12f 100644 --- a/src/data-structures/tree/__test__/BinaryTreeNode.test.js +++ b/src/data-structures/tree/__test__/BinaryTreeNode.test.js @@ -257,4 +257,41 @@ describe('BinaryTreeNode', () => { expect(child.uncle).toBeDefined(); expect(child.uncle).toEqual(uncle); }); + + it('should be possible to set node values', () => { + const node = new BinaryTreeNode('initial_value'); + + expect(node.value).toBe('initial_value'); + + node.setValue('new_value'); + + expect(node.value).toBe('new_value'); + }); + + it('should be possible to copy node', () => { + const root = new BinaryTreeNode('root'); + const left = new BinaryTreeNode('left'); + const right = new BinaryTreeNode('right'); + + root + .setLeft(left) + .setRight(right); + + expect(root.toString()).toBe('left,root,right'); + + const newRoot = new BinaryTreeNode('new_root'); + const newLeft = new BinaryTreeNode('new_left'); + const newRight = new BinaryTreeNode('new_right'); + + newRoot + .setLeft(newLeft) + .setRight(newRight); + + expect(newRoot.toString()).toBe('new_left,new_root,new_right'); + + BinaryTreeNode.copyNode(root, newRoot); + + expect(root.toString()).toBe('left,root,right'); + expect(newRoot.toString()).toBe('left,root,right'); + }); }); diff --git a/src/data-structures/tree/avl-tree/AvlTree.js b/src/data-structures/tree/avl-tree/AvlTree.js index b4b86ea474..51e6a05f92 100644 --- a/src/data-structures/tree/avl-tree/AvlTree.js +++ b/src/data-structures/tree/avl-tree/AvlTree.js @@ -16,6 +16,14 @@ export default class AvlTree extends BinarySearchTree { } } + /** + * @param {*} value + * @return {boolean} + */ + remove(value) { + throw new Error(`Can't remove ${value}. Remove method is not implemented yet`); + } + /** * @param {BinarySearchTreeNode} node */ diff --git a/src/data-structures/tree/avl-tree/__test__/AvlTRee.test.js b/src/data-structures/tree/avl-tree/__test__/AvlTRee.test.js index 5be7d119e9..fb1f3ee413 100644 --- a/src/data-structures/tree/avl-tree/__test__/AvlTRee.test.js +++ b/src/data-structures/tree/avl-tree/__test__/AvlTRee.test.js @@ -229,4 +229,14 @@ describe('AvlTree', () => { expect(tree.toString()).toBe('10,15,18,30,35,40,42,43,45,47'); expect(tree.root.height).toBe(3); }); + + it('should throw an error when trying to remove the node', () => { + const removeNodeAvlTree = () => { + const tree = new AvlTree(); + + tree.remove(1); + }; + + expect(removeNodeAvlTree).toThrowError(); + }); }); diff --git a/src/data-structures/tree/binary-search-tree/BinarySearchTree.js b/src/data-structures/tree/binary-search-tree/BinarySearchTree.js index e70950f916..b9e2ddad53 100644 --- a/src/data-structures/tree/binary-search-tree/BinarySearchTree.js +++ b/src/data-structures/tree/binary-search-tree/BinarySearchTree.js @@ -29,7 +29,7 @@ export default class BinarySearchTree { /** * @param {*} value - * @return {BinarySearchTreeNode} + * @return {boolean} */ remove(value) { return this.root.remove(value); diff --git a/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js index d6fe4bae97..36126a9c1f 100644 --- a/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js +++ b/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js @@ -81,7 +81,7 @@ export default class BinarySearchTreeNode extends BinaryTreeNode { /** * @param {*} value - * @return {BinarySearchTreeNode} + * @return {boolean} */ remove(value) { const nodeToRemove = this.find(value); @@ -94,8 +94,13 @@ export default class BinarySearchTreeNode extends BinaryTreeNode { if (!nodeToRemove.left && !nodeToRemove.right) { // Node is a leaf and thus has no children. - // Just remove the pointer to this node from the parent node. - parent.removeChild(nodeToRemove); + if (parent) { + // Node has a parent. Just remove the pointer to this node from the parent. + parent.removeChild(nodeToRemove); + } else { + // Node has no parent. Just erase current node value. + nodeToRemove.setValue(undefined); + } } else if (nodeToRemove.left && nodeToRemove.right) { // Node has two children. // Find the next biggest value (minimum value in the right branch) @@ -103,24 +108,27 @@ export default class BinarySearchTreeNode extends BinaryTreeNode { const nextBiggerNode = nodeToRemove.right.findMin(); if (!this.nodeComparator.equal(nextBiggerNode, nodeToRemove.right)) { this.remove(nextBiggerNode.value); - nodeToRemove.value = nextBiggerNode.value; + nodeToRemove.setValue(nextBiggerNode.value); } else { // In case if next right value is the next bigger one and it doesn't have left child // then just replace node that is going to be deleted with the right node. - nodeToRemove.value = nodeToRemove.right.value; - nodeToRemove.right = nodeToRemove.right.right; + nodeToRemove.setValue(nodeToRemove.right.value); + nodeToRemove.setRight(nodeToRemove.right.right); } } else { // Node has only one child. // Make this child to be a direct child of current node's parent. - if (nodeToRemove.left) { - parent.replaceChild(nodeToRemove, nodeToRemove.left); + /** @var BinarySearchTreeNode */ + const childNode = nodeToRemove.left || nodeToRemove.right; + + if (parent) { + parent.replaceChild(nodeToRemove, childNode); } else { - parent.replaceChild(nodeToRemove, nodeToRemove.right); + BinaryTreeNode.copyNode(childNode, nodeToRemove); } } - return nodeToRemove; + return true; } /** diff --git a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js index 593014d80b..981a118d9e 100644 --- a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js +++ b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js @@ -43,13 +43,13 @@ describe('BinarySearchTree', () => { expect(bst.toString()).toBe('5,10,20'); - const removedNode1 = bst.remove(5); + const removed1 = bst.remove(5); expect(bst.toString()).toBe('10,20'); - expect(removedNode1.value).toBe(5); + expect(removed1).toBeTruthy(); - const removedNode2 = bst.remove(20); + const removed2 = bst.remove(20); expect(bst.toString()).toBe('10'); - expect(removedNode2.value).toBe(20); + expect(removed2).toBeTruthy(); }); it('should insert object values', () => { diff --git a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js index 35a7fc53d0..63b9d999d6 100644 --- a/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js +++ b/src/data-structures/tree/binary-search-tree/__test__/BinarySearchTreeNode.test.js @@ -125,13 +125,13 @@ describe('BinarySearchTreeNode', () => { expect(bstRootNode.toString()).toBe('5,10,20'); - const removedNode1 = bstRootNode.remove(5); + const removed1 = bstRootNode.remove(5); expect(bstRootNode.toString()).toBe('10,20'); - expect(removedNode1.value).toBe(5); + expect(removed1).toBeTruthy(); - const removedNode2 = bstRootNode.remove(20); + const removed2 = bstRootNode.remove(20); expect(bstRootNode.toString()).toBe('10'); - expect(removedNode2.value).toBe(20); + expect(removed2).toBeTruthy(); }); it('should remove nodes with one child', () => { @@ -185,6 +185,21 @@ describe('BinarySearchTreeNode', () => { expect(bstRootNode.toString()).toBe('30'); }); + it('should remove node with no parent', () => { + const bstRootNode = new BinarySearchTreeNode(); + expect(bstRootNode.toString()).toBe(''); + + bstRootNode.insert(1); + bstRootNode.insert(2); + expect(bstRootNode.toString()).toBe('1,2'); + + bstRootNode.remove(1); + expect(bstRootNode.toString()).toBe('2'); + + bstRootNode.remove(2); + expect(bstRootNode.toString()).toBe(''); + }); + it('should throw error when trying to remove not existing node', () => { const bstRootNode = new BinarySearchTreeNode(); diff --git a/src/data-structures/tree/red-black-tree/RedBlackTree.js b/src/data-structures/tree/red-black-tree/RedBlackTree.js index 2bd3afd46c..6bb47130c8 100644 --- a/src/data-structures/tree/red-black-tree/RedBlackTree.js +++ b/src/data-structures/tree/red-black-tree/RedBlackTree.js @@ -34,7 +34,7 @@ export default class RedBlackTree extends BinarySearchTree { /** * @param {*} value - * @return {BinarySearchTreeNode} + * @return {boolean} */ remove(value) { throw new Error(`Can't remove ${value}. Remove method is not implemented yet`);