给出两个字符串 str1 和 str2,返回同时以 str1 和 str2 作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。
(如果从字符串 T 中删除一些字符(也可能不删除,并且选出的这些字符可以位于 T 中的 任意位置),可以得到字符串 S,那么 S 就是 T 的子序列)
示例:
输入:str1 = "abac", str2 = "cab"
输出:"cabac"
解释:
str1 = "abac" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 的第一个 "c"得到 "abac"。
str2 = "cab" 是 "cabac" 的一个子串,因为我们可以删去 "cabac" 末尾的 "ac" 得到 "cab"。
最终我们给出的答案是满足上述属性的最短字符串。
提示:
1 <= str1.length, str2.length <= 1000
str1 和 str2 都由小写英文字母组成。
思路:最长公共子序列变形题,我们知道答案分三部分,分别为公共部分、str1独有的部分和str2独有的部分。我们通过最长公共子序列的做法预处理出两个串最长公共子序列,然后按顺序添加这三个部分即可。
class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
int n = str1.length();
int m = str2.length();
String[][] dp = new String[n + 1][m + 1];
for (int i = 0; i <= n; i++)
for (int j = 0; j <= m; j++)
dp[i][j] = "";
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] = dp[i - 1][j - 1] + "" + str1.charAt(i - 1);
else
dp[i][j] = dp[i - 1][j].length() > dp[i][j - 1].length() ? dp[i - 1][j] : dp[i][j - 1];
}
int i = 0, j = 0;
char[] c_list = dp[n][m].toCharArray();
StringBuilder ans = new StringBuilder();
for (char c : c_list) {
while (i < n && str1.charAt(i) != c)
ans.append(str1.charAt(i++));
while (j < m && str2.charAt(j) != c)
ans.append(str2.charAt(j++));
if (i < n) ans.append(str1.charAt(i));
i++; j++;
}
while (i < n) ans.append(str1.charAt(i++));
while (j < m) ans.append(str2.charAt(j++));
return ans.toString();
}
}