Skip to content

Commit 9bef8de

Browse files
committedApr 26, 2018
Add LCS.
1 parent a672474 commit 9bef8de

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed
 

‎README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* [Knuth–Morris–Pratt Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/knuth-morris-pratt) - substring search
4545
* [Rabin Karp Algorithm](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/rabin-karp) - substring search
4646
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-subsequnce) (LCS)
47-
* longest common substring
47+
* [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring)
4848
* **Search**
4949
* [Binary Search](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/search/binary-search)
5050
* **Sorting**
@@ -74,6 +74,7 @@
7474
* **Dynamic Programming**
7575
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
7676
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-subsequnce) (LCS)
77+
* [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring)
7778
* Increasing subsequence
7879
* Knapsack problem
7980
* Maximum subarray
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Longest Common Substring Problem
2+
3+
The longest common substring problem is to find the longest string
4+
(or strings) that is a substring (or are substrings) of two or more
5+
strings.
6+
7+
## Example
8+
9+
The longest common substring of the strings `ABABC`, `BABCA` and
10+
`ABCBA` is string `ABC` of length 3. Other common substrings are
11+
`A`, `AB`, `B`, `BA`, `BC` and `C`.
12+
13+
```
14+
ABABC
15+
|||
16+
BABCA
17+
|||
18+
ABCBA
19+
```
20+
21+
## References
22+
23+
- [Wikipedia](https://en.wikipedia.org/wiki/Longest_common_substring_problem)
24+
- [YouTube](https://www.youtube.com/watch?v=BysNXJHzCEs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import longestCommonSubstring from '../longestCommonSubstring';
2+
3+
describe('longestCommonSubstring', () => {
4+
it('should find longest common substring between two strings', () => {
5+
expect(longestCommonSubstring('', '')).toBe('');
6+
expect(longestCommonSubstring('ABC', '')).toBe('');
7+
expect(longestCommonSubstring('', 'ABC')).toBe('');
8+
expect(longestCommonSubstring('ABABC', 'BABCA')).toBe('BABC');
9+
expect(longestCommonSubstring('BABCA', 'ABCBA')).toBe('ABC');
10+
});
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @param {string} s1
3+
* @param {string} s2
4+
* @return {string}
5+
*/
6+
export default function longestCommonSubstring(s1, s2) {
7+
// Init the matrix of all substring lengths to use Dynamic Programming approach.
8+
const substringMatrix = Array(s2.length + 1).fill(null).map(() => {
9+
return Array(s1.length + 1).fill(null);
10+
});
11+
12+
// Fill the first row and first column with zeros to provide initial values.
13+
for (let columnIndex = 0; columnIndex <= s1.length; columnIndex += 1) {
14+
substringMatrix[0][columnIndex] = 0;
15+
}
16+
17+
for (let rowIndex = 0; rowIndex <= s2.length; rowIndex += 1) {
18+
substringMatrix[rowIndex][0] = 0;
19+
}
20+
21+
// Build the matrix of all substring lengths to use Dynamic Programming approach.
22+
let longestSubstringLength = 0;
23+
let longestSubstringColumn = 0;
24+
let longestSubstringRow = 0;
25+
26+
for (let rowIndex = 1; rowIndex <= s2.length; rowIndex += 1) {
27+
for (let columnIndex = 1; columnIndex <= s1.length; columnIndex += 1) {
28+
if (s1[columnIndex - 1] === s2[rowIndex - 1]) {
29+
substringMatrix[rowIndex][columnIndex] = substringMatrix[rowIndex - 1][columnIndex - 1] + 1;
30+
} else {
31+
substringMatrix[rowIndex][columnIndex] = 0;
32+
}
33+
34+
// Try to find the biggest length of all common substring lengths
35+
// and to memorize its last character position (indices)
36+
if (substringMatrix[rowIndex][columnIndex] > longestSubstringLength) {
37+
longestSubstringLength = substringMatrix[rowIndex][columnIndex];
38+
longestSubstringColumn = columnIndex;
39+
longestSubstringRow = rowIndex;
40+
}
41+
}
42+
}
43+
44+
if (longestSubstringLength === 0) {
45+
// Longest common substring has not been found.
46+
return '';
47+
}
48+
49+
// Detect the longest substring from the matrix.
50+
let longestSubstring = '';
51+
52+
while (substringMatrix[longestSubstringRow][longestSubstringColumn] > 0) {
53+
longestSubstring = s1[longestSubstringColumn - 1] + longestSubstring;
54+
longestSubstringRow -= 1;
55+
longestSubstringColumn -= 1;
56+
}
57+
58+
return longestSubstring;
59+
}

0 commit comments

Comments
 (0)
Please sign in to comment.