mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 23:21:18 +08:00
Add LCS.
This commit is contained in:
parent
0e46d3e164
commit
bf24ea3316
@ -39,11 +39,11 @@
|
|||||||
* [Least Common Multiple](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM)
|
* [Least Common Multiple](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/least-common-multiple) (LCM)
|
||||||
* [Fisher–Yates Shuffle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fisher-yates) - random permutation of a finite sequence
|
* [Fisher–Yates Shuffle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/fisher-yates) - random permutation of a finite sequence
|
||||||
* **String**
|
* **String**
|
||||||
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences (DP approach)
|
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences (dynamic programming approach)
|
||||||
* [Hamming Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
|
* [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
|
* [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
|
* [Rabin Karp Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/rabin-karp) - substring search
|
||||||
* Longest common subsequence
|
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-subsequnce) (LCS)
|
||||||
* longest common substring
|
* longest common substring
|
||||||
* **Search**
|
* **Search**
|
||||||
* [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search)
|
* [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search)
|
||||||
|
25
src/algorithms/string/longest-common-subsequnce/README.md
Normal file
25
src/algorithms/string/longest-common-subsequnce/README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Longest common subsequence problem
|
||||||
|
|
||||||
|
The longest common subsequence (LCS) problem is the problem of finding
|
||||||
|
the longest subsequence common to all sequences in a set of sequences
|
||||||
|
(often just two sequences). It differs from the longest common substring
|
||||||
|
problem: unlike substrings, subsequences are not required to occupy
|
||||||
|
consecutive positions within the original sequences.
|
||||||
|
|
||||||
|
## Application
|
||||||
|
|
||||||
|
The longest common subsequence problem is a classic computer science
|
||||||
|
problem, the basis of data comparison programs such as the diff utility,
|
||||||
|
and has applications in bioinformatics. It is also widely used by
|
||||||
|
revision control systems such as Git for reconciling multiple changes
|
||||||
|
made to a revision-controlled collection of files.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
- LCS for input Sequences `ABCDGH` and `AEDFHR` is `ADH` of length 3.
|
||||||
|
- LCS for input Sequences `AGGTAB` and `GXTXAYB` is `GTAB` of length 4.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem)
|
||||||
|
- [YouTube](https://www.youtube.com/watch?v=NnD96abizww)
|
@ -0,0 +1,13 @@
|
|||||||
|
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');
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @param {string} s1
|
||||||
|
* @param {string} s2
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
export default function longestCommonSubsequnce(s1, s2) {
|
||||||
|
// Init LCS matrix.
|
||||||
|
const lcsMatrix = Array(s2.length + 1).fill(null).map(() => Array(s1.length + 1).fill(null));
|
||||||
|
|
||||||
|
// Fill first row with zeros.
|
||||||
|
for (let columnIndex = 0; columnIndex <= s1.length; columnIndex += 1) {
|
||||||
|
lcsMatrix[0][columnIndex] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill first column with zeros.
|
||||||
|
for (let rowIndex = 0; rowIndex <= s2.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]) {
|
||||||
|
lcsMatrix[rowIndex][columnIndex] = lcsMatrix[rowIndex - 1][columnIndex - 1] + 1;
|
||||||
|
} else {
|
||||||
|
lcsMatrix[rowIndex][columnIndex] = Math.max(
|
||||||
|
lcsMatrix[rowIndex - 1][columnIndex],
|
||||||
|
lcsMatrix[rowIndex][columnIndex - 1],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate LCS based on LCS matrix.
|
||||||
|
if (!lcsMatrix[s2.length][s1.length]) {
|
||||||
|
// If the length of largest common string is zero then return empty string.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let lcs = '';
|
||||||
|
let columnIndex = s1.length;
|
||||||
|
let rowIndex = s2.length;
|
||||||
|
|
||||||
|
while (columnIndex > 0 || rowIndex > 0) {
|
||||||
|
if (s1[columnIndex - 1] === s2[rowIndex - 1]) {
|
||||||
|
// Move by diagonal left-top.
|
||||||
|
lcs = s1[columnIndex - 1] + lcs;
|
||||||
|
columnIndex -= 1;
|
||||||
|
rowIndex -= 1;
|
||||||
|
} else if (lcsMatrix[rowIndex][columnIndex] === lcsMatrix[rowIndex][columnIndex - 1]) {
|
||||||
|
// Move left.
|
||||||
|
columnIndex -= 1;
|
||||||
|
} else {
|
||||||
|
// Move up.
|
||||||
|
rowIndex -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lcs;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user