diff --git a/README.md b/README.md index dd47a80b..3cbfe6cd 100644 --- a/README.md +++ b/README.md @@ -38,13 +38,13 @@ * [Power Set](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/power-set) - all subsets of the 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 + * [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-subsequnce) (LCS) * **String** * [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 Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-subsequnce) (LCS) * [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring) * **Search** * [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search) @@ -90,7 +90,7 @@ * **Dynamic Programming** * [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/string/longest-common-subsequnce) (LCS) + * [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) * Increasing subsequence * Longest Increasing subsequence diff --git a/src/algorithms/string/longest-common-subsequnce/README.md b/src/algorithms/sets/longest-common-subsequnce/README.md similarity index 100% rename from src/algorithms/string/longest-common-subsequnce/README.md rename to src/algorithms/sets/longest-common-subsequnce/README.md diff --git a/src/algorithms/sets/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js b/src/algorithms/sets/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js new file mode 100644 index 00000000..01d84cab --- /dev/null +++ b/src/algorithms/sets/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js @@ -0,0 +1,31 @@ +import longestCommonSubsequnce from '../longestCommonSubsequnce'; + +describe('longestCommonSubsequnce', () => { + it('should find longest common subsequence for two strings', () => { + expect(longestCommonSubsequnce([''], [''])).toEqual(['']); + + expect(longestCommonSubsequnce([''], ['A', 'B', 'C'])).toEqual(['']); + + expect(longestCommonSubsequnce(['A', 'B', 'C'], [''])).toEqual(['']); + + expect(longestCommonSubsequnce( + ['A', 'B', 'C'], + ['D', 'E', 'F', 'G'], + )).toEqual(['']); + + expect(longestCommonSubsequnce( + ['A', 'B', 'C', 'D', 'G', 'H'], + ['A', 'E', 'D', 'F', 'H', 'R'], + )).toEqual(['A', 'D', 'H']); + + expect(longestCommonSubsequnce( + ['A', 'G', 'G', 'T', 'A', 'B'], + ['G', 'X', 'T', 'X', 'A', 'Y', 'B'], + )).toEqual(['G', 'T', 'A', 'B']); + + expect(longestCommonSubsequnce( + ['A', 'B', 'C', 'D', 'A', 'F'], + ['A', 'C', 'B', 'C', 'F'], + )).toEqual(['A', 'B', 'C', 'F']); + }); +}); diff --git a/src/algorithms/string/longest-common-subsequnce/longestCommonSubsequnce.js b/src/algorithms/sets/longest-common-subsequnce/longestCommonSubsequnce.js similarity index 53% rename from src/algorithms/string/longest-common-subsequnce/longestCommonSubsequnce.js rename to src/algorithms/sets/longest-common-subsequnce/longestCommonSubsequnce.js index 94c6c4d9..440fe767 100644 --- a/src/algorithms/string/longest-common-subsequnce/longestCommonSubsequnce.js +++ b/src/algorithms/sets/longest-common-subsequnce/longestCommonSubsequnce.js @@ -1,26 +1,26 @@ /** - * @param {string} s1 - * @param {string} s2 - * @return {string} + * @param {string[]} set1 + * @param {string[]} set2 + * @return {string[]} */ -export default function longestCommonSubsequnce(s1, s2) { +export default function longestCommonSubsequnce(set1, set2) { // Init LCS matrix. - const lcsMatrix = Array(s2.length + 1).fill(null).map(() => Array(s1.length + 1).fill(null)); + const lcsMatrix = Array(set2.length + 1).fill(null).map(() => Array(set1.length + 1).fill(null)); // Fill first row with zeros. - for (let columnIndex = 0; columnIndex <= s1.length; columnIndex += 1) { + for (let columnIndex = 0; columnIndex <= set1.length; columnIndex += 1) { lcsMatrix[0][columnIndex] = 0; } // Fill first column with zeros. - for (let rowIndex = 0; rowIndex <= s2.length; rowIndex += 1) { + for (let rowIndex = 0; rowIndex <= set2.length; rowIndex += 1) { lcsMatrix[rowIndex][0] = 0; } // Fill rest of the column that correspond to each of two strings. - for (let rowIndex = 1; rowIndex <= s2.length; rowIndex += 1) { - for (let columnIndex = 1; columnIndex <= s1.length; columnIndex += 1) { - if (s1[columnIndex - 1] === s2[rowIndex - 1]) { + for (let rowIndex = 1; rowIndex <= set2.length; rowIndex += 1) { + for (let columnIndex = 1; columnIndex <= set1.length; columnIndex += 1) { + if (set1[columnIndex - 1] === set2[rowIndex - 1]) { lcsMatrix[rowIndex][columnIndex] = lcsMatrix[rowIndex - 1][columnIndex - 1] + 1; } else { lcsMatrix[rowIndex][columnIndex] = Math.max( @@ -32,19 +32,19 @@ export default function longestCommonSubsequnce(s1, s2) { } // Calculate LCS based on LCS matrix. - if (!lcsMatrix[s2.length][s1.length]) { + if (!lcsMatrix[set2.length][set1.length]) { // If the length of largest common string is zero then return empty string. - return ''; + return ['']; } - let lcs = ''; - let columnIndex = s1.length; - let rowIndex = s2.length; + const longestSequence = []; + let columnIndex = set1.length; + let rowIndex = set2.length; while (columnIndex > 0 || rowIndex > 0) { - if (s1[columnIndex - 1] === s2[rowIndex - 1]) { + if (set1[columnIndex - 1] === set2[rowIndex - 1]) { // Move by diagonal left-top. - lcs = s1[columnIndex - 1] + lcs; + longestSequence.unshift(set1[columnIndex - 1]); columnIndex -= 1; rowIndex -= 1; } else if (lcsMatrix[rowIndex][columnIndex] === lcsMatrix[rowIndex][columnIndex - 1]) { @@ -56,5 +56,5 @@ export default function longestCommonSubsequnce(s1, s2) { } } - return lcs; + return longestSequence; } diff --git a/src/algorithms/string/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js b/src/algorithms/string/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js deleted file mode 100644 index 7be969ee..00000000 --- a/src/algorithms/string/longest-common-subsequnce/__test__/longestCommonSubsequnce.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import longestCommonSubsequnce from '../longestCommonSubsequnce'; - -describe('longestCommonSubsequnce', () => { - it('should find longest common subsequence for two strings', () => { - expect(longestCommonSubsequnce('', '')).toBe(''); - expect(longestCommonSubsequnce('', 'ABC')).toBe(''); - expect(longestCommonSubsequnce('ABC', '')).toBe(''); - expect(longestCommonSubsequnce('ABC', 'DEFG')).toBe(''); - expect(longestCommonSubsequnce('ABCDGH', 'AEDFHR')).toBe('ADH'); - expect(longestCommonSubsequnce('AGGTAB', 'GXTXAYB')).toBe('GTAB'); - expect(longestCommonSubsequnce('ABCDAF', 'ACBCF')).toBe('ABCF'); - }); -});