Shortest Common Super Sequence
Problem Link
LeetCode: Shortest Common Supersequence
Problem Statement
Given two strings str1 and str2, return the shortest string that has both str1 and str2 as subsequences. If multiple such strings exist, return any of them.
Intuition
We want to merge both strings while avoiding repetition of common characters.
Use LCS (Longest Common Subsequence) to find the overlapping parts and then build the SCS.
Length of SCS = str1.length() + str2.length() - LCS(str1, str2)
1. Recursion
Concept
We define f(i, j) as the shortest supersequence of str1[0..i] and str2[0..j].
Choice Diagram (IBH)
-
If str1[i] == str2[j]: Include it once and recurse diagonally.
-
Else: We have two options:
-
Include
str1[i]and move tof(i-1, j) -
Include
str2[j]and move tof(i, j-1) -
Choose the shorter result.
-
Java Code: Recursion
public class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
return scs(str1, str2, str1.length() - 1, str2.length() - 1);
}
private String scs(String s1, String s2, int i, int j) {
if (i < 0) return s2.substring(0, j + 1);
if (j < 0) return s1.substring(0, i + 1);
if (s1.charAt(i) == s2.charAt(j)) {
return scs(s1, s2, i - 1, j - 1) + s1.charAt(i);
} else {
String pick1 = scs(s1, s2, i - 1, j) + s1.charAt(i);
String pick2 = scs(s1, s2, i, j - 1) + s2.charAt(j);
return pick1.length() < pick2.length() ? pick1 : pick2;
}
}
}
Time Complexity: Exponential — O(2^(m+n))
2. Memoization (Top-Down DP)
Java Code: Memoization
public class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
int n = str1.length(), m = str2.length();
String[][] dp = new String[n][m];
return scs(str1, str2, n - 1, m - 1, dp);
}
private String scs(String s1, String s2, int i, int j, String[][] dp) {
if (i < 0) return s2.substring(0, j + 1);
if (j < 0) return s1.substring(0, i + 1);
if (dp[i][j] != null) return dp[i][j];
if (s1.charAt(i) == s2.charAt(j)) {
return dp[i][j] = scs(s1, s2, i - 1, j - 1, dp) + s1.charAt(i);
} else {
String pick1 = scs(s1, s2, i - 1, j, dp) + s1.charAt(i);
String pick2 = scs(s1, s2, i, j - 1, dp) + s2.charAt(j);
return dp[i][j] = pick1.length() < pick2.length() ? pick1 : pick2;
}
}
}
Time Complexity: O(m × n × (m+n)) (due to string building)
3. Tabulation (Bottom-Up DP) + Reconstruction
Java Code
public class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
int n = str1.length(), m = str2.length();
int[][] dp = new int[n + 1][m + 1];
// Step 1: LCS Table
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = 1 + dp[i - 1][j - 1];
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// Step 2: Reconstruct SCS from LCS table
StringBuilder sb = new StringBuilder();
int i = n, j = m;
while (i > 0 && j > 0) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
sb.append(str1.charAt(i - 1));
i--; j--;
} else if (dp[i - 1][j] > dp[i][j - 1]) {
sb.append(str1.charAt(i - 1));
i--;
} else {
sb.append(str2.charAt(j - 1));
j--;
}
}
while (i > 0) sb.append(str1.charAt(--i));
while (j > 0) sb.append(str2.charAt(--j));
return sb.reverse().toString();
}
}
Dry Run Example
str1 = "abac", str2 = "cab"
LCS = "ab"
SCS = "cabac"
Time and Space Complexity
| Approach | Time | Space |
|---|---|---|
| Recursion | O(2^(n+m)) | O(n+m) |
| Memoization | O(n×m) | O(n×m) |
| Tabulation | O(n×m) | O(n×m) |
Summary
-
We use LCS to avoid repeating characters.
-
For printing the actual SCS, we trace back the LCS table while merging characters.
-
Reconstructing the answer gives the shortest possible sequence containing both strings as subsequences.