Welcome to Subscribe On Youtube
Formatted question description: https://leetcode.ca/all/1092.html
1092. Shortest Common Supersequence (Hard)
Given two strings str1
and str2
, return the shortest string that has both str1
and str2
as subsequences. If multiple answers exist, you may return any of them.
(A string S is a subsequence of string T if deleting some number of characters from T (possibly 0, and the characters are chosen anywhere from T) results in the string S.)
Example 1:
Input: str1 = "abac", str2 = "cab" Output: "cabac" Explanation: str1 = "abac" is a subsequence of "cabac" because we can delete the first "c". str2 = "cab" is a subsequence of "cabac" because we can delete the last "ac". The answer provided is the shortest such string that satisfies these properties.
Note:
1 <= str1.length, str2.length <= 1000
str1
andstr2
consist of lowercase English letters.
Related Topics:
Dynamic Programming
Similar Questions:
Solution 1. DP
Let dp[i][j]
be the length of the shortest common supersequence of s[0..(i-1)]
and t[0..(j-1)]
.
dp[i][j] = 1 + dp[i-1][j-1] if s[i-1] == t[j-1]
1 + min(dp[i-1][j], dp[i][j-1]) if s[i-1] != t[j-1]
dp[0][i] = dp[i][0] = i
dp[M][N]
is the length of the shortest common supersequence of s
and t
.
With this dp
array, we can construct the shortest common supersequence.
// OJ: https://leetcode.com/problems/shortest-common-supersequence/
// Time: O(MN)
// Space: O(MN)
class Solution {
public:
string shortestCommonSupersequence(string s, string t) {
int M = s.size(), N = t.size();
vector<vector<int>> dp(M + 1, vector<int>(N + 1));
for (int i = 1; i <= N; ++i) dp[0][i] = i;
for (int i = 1; i <= M; ++i) dp[i][0] = i;
for (int i = 1; i <= M; ++i) {
for (int j = 1; j <= N; ++j) {
if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]);
}
}
string ans(dp[M][N], ' ');
for (int i = M, j = N, k = ans.size() - 1; k >= 0; --k) {
if (i && j && s[i - 1] == t[j - 1]) ans[k] = s[--i], --j;
else if (i && dp[i][j] == dp[i - 1][j] + 1) ans[k] = s[--i];
else ans[k] = t[--j];
}
return ans;
}
};
Solution 2. LCS
Let dp[i][j]
be the length of longest common subsequence of s[0..(i-1)]
and t[0..(j-1)]
.
dp[i][j] = 1 + dp[i-1][j-1] if s[i-1] == t[j-1]
max(dp[i-1][j], dp[i][j-1]) if s[i-1] != t[j-1]
dp[0][i] = dp[i][0] = 0
dp[M][N]
is the length of the LCS of s
and t
, and M + N - dp[M][N]
is the length of the shortest common supersequence.
We can use dp
array to construct the shortest common supersequence as well.
// OJ: https://leetcode.com/problems/shortest-common-supersequence/
// Time: O(MN)
// Space: O(MN)
// Ref: https://leetcode.com/problems/shortest-common-supersequence/discuss/312757/JavaPython-3-O(mn)-clean-DP-code-w-picture-comments-and-analysis.
class Solution {
public:
string shortestCommonSupersequence(string s, string t) {
int M = s.size(), N = t.size();
vector<vector<int>> dp(M + 1, vector<int>(N + 1));
for (int i = 1; i <= M; ++i) {
for (int j = 1; j <= N; ++j) {
if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
string ans(M + N - dp[M][N], ' ');
for (int i = M, j = N, k = ans.size() - 1; k >= 0; --k) {
if (i && j && s[i - 1] == t[j - 1]) ans[k] = s[--i], --j;
else if (i && dp[i][j] == dp[i - 1][j]) ans[k] = s[--i];
else ans[k] = t[--j];
}
return ans;
}
};
-
class Solution { public String shortestCommonSupersequence(String str1, String str2) { int length1 = str1.length(), length2 = str2.length(); int[][] dp = new int[length1 + 1][length2 + 1]; for (int i = 1; i <= length1; i++) { char c1 = str1.charAt(i - 1); for (int j = 1; j <= length2; j++) { char c2 = str2.charAt(j - 1); if (c1 == c2) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } int longestCommonSubsequenceLength = dp[length1][length2]; StringBuffer sb = new StringBuffer(); int index1 = length1, index2 = length2; while (index1 > 0 && index2 > 0) { char c1 = str1.charAt(index1 - 1), c2 = str2.charAt(index2 - 1); if (c1 == c2) { sb.append(c1); longestCommonSubsequenceLength--; index1--; index2--; } else if (dp[index1 - 1][index2] == longestCommonSubsequenceLength) { sb.append(c1); index1--; } else { sb.append(c2); index2--; } } while (index1 > 0) { sb.append(str1.charAt(index1 - 1)); index1--; } while (index2 > 0) { sb.append(str2.charAt(index2 - 1)); index2--; } return sb.reverse().toString(); } } ############ class Solution { public String shortestCommonSupersequence(String str1, String str2) { int m = str1.length(), n = str2.length(); int[][] f = new int[m + 1][n + 1]; for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (str1.charAt(i - 1) == str2.charAt(j - 1)) { f[i][j] = f[i - 1][j - 1] + 1; } else { f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]); } } } int i = m, j = n; StringBuilder ans = new StringBuilder(); while (i > 0 || j > 0) { if (i == 0) { ans.append(str2.charAt(--j)); } else if (j == 0) { ans.append(str1.charAt(--i)); } else { if (f[i][j] == f[i - 1][j]) { ans.append(str1.charAt(--i)); } else if (f[i][j] == f[i][j - 1]) { ans.append(str2.charAt(--j)); } else { ans.append(str1.charAt(--i)); --j; } } } return ans.reverse().toString(); } }
-
// OJ: https://leetcode.com/problems/shortest-common-supersequence/ // Time: O(MN) // Space: O(MN) class Solution { public: string shortestCommonSupersequence(string s, string t) { int M = s.size(), N = t.size(); vector<vector<int>> dp(M + 1, vector<int>(N + 1)); for (int i = 1; i <= N; ++i) dp[0][i] = i; for (int i = 1; i <= M; ++i) dp[i][0] = i; for (int i = 1; i <= M; ++i) { for (int j = 1; j <= N; ++j) { if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]); } } string ans(dp[M][N], ' '); for (int i = M, j = N, k = ans.size() - 1; k >= 0; --k) { if (i && j && s[i - 1] == t[j - 1]) ans[k] = s[--i], --j; else if (i && dp[i][j] == dp[i - 1][j] + 1) ans[k] = s[--i]; else ans[k] = t[--j]; } return ans; } };
-
class Solution: def shortestCommonSupersequence(self, str1: str, str2: str) -> str: m, n = len(str1), len(str2) f = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if str1[i - 1] == str2[j - 1]: f[i][j] = f[i - 1][j - 1] + 1 else: f[i][j] = max(f[i - 1][j], f[i][j - 1]) ans = [] i, j = m, n while i or j: if i == 0: j -= 1 ans.append(str2[j]) elif j == 0: i -= 1 ans.append(str1[i]) else: if f[i][j] == f[i - 1][j]: i -= 1 ans.append(str1[i]) elif f[i][j] == f[i][j - 1]: j -= 1 ans.append(str2[j]) else: i, j = i - 1, j - 1 ans.append(str1[i]) return ''.join(ans[::-1]) ############ # 1092. Shortest Common Supersequence # https://leetcode.com/problems/shortest-common-supersequence/ class Solution: def shortestCommonSupersequence(self, A: str, B: str) -> str: def lcs(): m, n = len(A), len(B) dp = [[""] * (n + 1) for _ in range(m + 1)] for i in range(m): for j in range(n): if A[i] == B[j]: dp[i + 1][j + 1] = dp[i][j] + A[i] else: dp[i + 1][j + 1] += max(dp[i + 1][j], dp[i][j + 1], key = len) return dp[-1][-1] res, i, j = '', 0, 0 for c in lcs(): while A[i] != c: res += A[i] i += 1 while B[j] != c: res += B[j] j += 1 res += c i, j = i + 1, j + 1 return res + A[i:] + B[j:]
-
func shortestCommonSupersequence(str1 string, str2 string) string { m, n := len(str1), len(str2) f := make([][]int, m+1) for i := range f { f[i] = make([]int, n+1) } for i := 1; i <= m; i++ { for j := 1; j <= n; j++ { if str1[i-1] == str2[j-1] { f[i][j] = f[i-1][j-1] + 1 } else { f[i][j] = max(f[i-1][j], f[i][j-1]) } } } ans := []byte{} i, j := m, n for i > 0 || j > 0 { if i == 0 { j-- ans = append(ans, str2[j]) } else if j == 0 { i-- ans = append(ans, str1[i]) } else { if f[i][j] == f[i-1][j] { i-- ans = append(ans, str1[i]) } else if f[i][j] == f[i][j-1] { j-- ans = append(ans, str2[j]) } else { i, j = i-1, j-1 ans = append(ans, str1[i]) } } } for i, j = 0, len(ans)-1; i < j; i, j = i+1, j-1 { ans[i], ans[j] = ans[j], ans[i] } return string(ans) } func max(a, b int) int { if a > b { return a } return b }
-
function shortestCommonSupersequence(str1: string, str2: string): string { const m = str1.length; const n = str2.length; const f = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0)); for (let i = 1; i <= m; ++i) { for (let j = 1; j <= n; ++j) { if (str1[i - 1] == str2[j - 1]) { f[i][j] = f[i - 1][j - 1] + 1; } else { f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]); } } } let ans: string[] = []; let i = m; let j = n; while (i > 0 || j > 0) { if (i === 0) { ans.push(str2[--j]); } else if (j === 0) { ans.push(str1[--i]); } else { if (f[i][j] === f[i - 1][j]) { ans.push(str1[--i]); } else if (f[i][j] === f[i][j - 1]) { ans.push(str2[--j]); } else { ans.push(str1[--i]); --j; } } } return ans.reverse().join(''); }