Skip to content

Commit c9089bb

Browse files
committedApr 27, 2018
Add SCS.
1 parent 3a984b6 commit c9089bb

File tree

4 files changed

+132
-1
lines changed

4 files changed

+132
-1
lines changed
 

‎README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* [Fisher–Yates Shuffle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
4040
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS)
4141
* [Longest Increasing subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence)
42+
* [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence) (SCS)
4243
* **String**
4344
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
4445
* [Hamming Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
@@ -92,7 +93,7 @@
9293
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS)
9394
* [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring)
9495
* [Longest Increasing subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence)
95-
* Shortest common supersequence
96+
* [Shortest Common Supersequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/shortest-common-supersequence)
9697
* Knapsack problem
9798
* Maximum subarray
9899
* Maximum sum path
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Shortest Common Supersequence
2+
3+
The shortest common supersequence (SCS) of two sequences `X` and `Y`
4+
is the shortest sequence which has `X` and `Y` as subsequences.
5+
6+
In other words assume we're given two strings str1 and str2, find
7+
the shortest string that has both str1 and str2 as subsequences.
8+
9+
This is a problem closely related to the longest common
10+
subsequence problem.
11+
12+
## Example
13+
14+
```
15+
Input: str1 = "geek", str2 = "eke"
16+
Output: "geeke"
17+
18+
Input: str1 = "AGGTAB", str2 = "GXTXAYB"
19+
Output: "AGXGTXAYB"
20+
```
21+
22+
## References
23+
24+
- [GeeksForGeeks](https://www.geeksforgeeks.org/shortest-common-supersequence/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import shortestCommonSupersequence from '../shortestCommonSupersequence';
2+
3+
describe('shortestCommonSupersequence', () => {
4+
it('should find shortest common supersequence of two sequences', () => {
5+
// LCS (longest common subsequence) is empty
6+
expect(shortestCommonSupersequence(
7+
['A', 'B', 'C'],
8+
['D', 'E', 'F'],
9+
)).toEqual(['A', 'B', 'C', 'D', 'E', 'F']);
10+
11+
// LCS (longest common subsequence) is "EE"
12+
expect(shortestCommonSupersequence(
13+
['G', 'E', 'E', 'K'],
14+
['E', 'K', 'E'],
15+
)).toEqual(['G', 'E', 'K', 'E', 'K']);
16+
17+
// LCS (longest common subsequence) is "GTAB"
18+
expect(shortestCommonSupersequence(
19+
['A', 'G', 'G', 'T', 'A', 'B'],
20+
['G', 'X', 'T', 'X', 'A', 'Y', 'B'],
21+
)).toEqual(['A', 'G', 'G', 'X', 'T', 'X', 'A', 'Y', 'B']);
22+
23+
// LCS (longest common subsequence) is "BCBA".
24+
expect(shortestCommonSupersequence(
25+
['A', 'B', 'C', 'B', 'D', 'A', 'B'],
26+
['B', 'D', 'C', 'A', 'B', 'A'],
27+
)).toEqual(['A', 'B', 'D', 'C', 'A', 'B', 'D', 'A', 'B']);
28+
29+
// LCS (longest common subsequence) is "BDABA".
30+
expect(shortestCommonSupersequence(
31+
['B', 'D', 'C', 'A', 'B', 'A'],
32+
['A', 'B', 'C', 'B', 'D', 'A', 'B', 'A', 'C'],
33+
)).toEqual(['A', 'B', 'C', 'B', 'D', 'C', 'A', 'B', 'A', 'C']);
34+
});
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import longestCommonSubsequnce from '../longest-common-subsequnce/longestCommonSubsequnce';
2+
3+
/**
4+
* @param {string[]} set1
5+
* @param {string[]} set2
6+
* @return {string[]}
7+
*/
8+
9+
export default function shortestCommonSupersequence(set1, set2) {
10+
// Let's first find the longest common subsequence of two sets.
11+
const lcs = longestCommonSubsequnce(set1, set2);
12+
13+
// If LCS is empty then the shortest common supersequnce would be just
14+
// concatenation of two sequences.
15+
if (lcs.length === 1 && lcs[0] === '') {
16+
return set1.concat(set2);
17+
}
18+
19+
// Now let's add elements of set1 and set2 in order before/inside/after the LCS.
20+
let supersequence = [];
21+
22+
let setIndex1 = 0;
23+
let setIndex2 = 0;
24+
let lcsIndex = 0;
25+
let setOnHold1 = false;
26+
let setOnHold2 = false;
27+
28+
while (lcsIndex < lcs.length) {
29+
// Add elements of the first set to supersequence in correct order.
30+
if (setIndex1 < set1.length) {
31+
if (!setOnHold1 && set1[setIndex1] !== lcs[lcsIndex]) {
32+
supersequence.push(set1[setIndex1]);
33+
setIndex1 += 1;
34+
} else {
35+
setOnHold1 = true;
36+
}
37+
}
38+
39+
// Add elements of the second set to supersequence in correct order.
40+
if (setIndex2 < set2.length) {
41+
if (!setOnHold2 && set2[setIndex2] !== lcs[lcsIndex]) {
42+
supersequence.push(set2[setIndex2]);
43+
setIndex2 += 1;
44+
} else {
45+
setOnHold2 = true;
46+
}
47+
}
48+
49+
// Add LCS element to the supersequence in correct order.
50+
if (setOnHold1 && setOnHold2) {
51+
supersequence.push(lcs[lcsIndex]);
52+
lcsIndex += 1;
53+
setIndex1 += 1;
54+
setIndex2 += 1;
55+
setOnHold1 = false;
56+
setOnHold2 = false;
57+
}
58+
}
59+
60+
// Attach set1 leftovers.
61+
if (setIndex1 < set1.length) {
62+
supersequence = supersequence.concat(set1.slice(setIndex1));
63+
}
64+
65+
// Attach set2 leftovers.
66+
if (setIndex2 < set2.length) {
67+
supersequence = supersequence.concat(set2.slice(setIndex2));
68+
}
69+
70+
return supersequence;
71+
}

0 commit comments

Comments
 (0)
Please sign in to comment.