题目描述
给出两个字符串 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 都由小写英文字母组成。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shortest-common-supersequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
动态规划
定义dp[str1.length()+1][str2.length()+1]
状态:dp[i][j]表示以str1(i~末尾)和str2(j-末尾)作为子序列的最短字符串长度。
初始值:
dp数组从后往前构建
列边界值表示以str1子串和空字符串作为子序列的最短字符串长度,毫无疑问是str1子串的长度;
同理行边界值表示以空字符串和str2的子串作为子序列的最短字符串长度,毫无疑问是str2子串的长度。
状态转移方程:
如果str1.charAt(i)==str2.charAt(j)
dp[i][j]=dp[i+1][j+1]+1;
否则
dp[i][j]=Math.min(dp[i+1][j],dp[i][j+1])+1;
因为我们要求的是字符串
所以在构建dp的同时,可以把dp对应的string也定义出来。
定义strdp[m+1][n+1];
代码
class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
int m = str1.length();
int n = str2.length();
int[][] dp = new int[m+1][n+1];
String[][] strdp = new String[m+1][n+1];
for(int i=0;i<m+1;i++){
dp[i][n]=m-i;
if(i!=m){
strdp[i][n]=str1.substring(i);
}else{
strdp[i][n]="";
}
}
for(int j=0;j<n+1;j++){
dp[m][j]=n-j;
if(j!=n){
strdp[m][j]=str2.substring(j);
}else{
strdp[m][j]="";
}
}
for(int i=m-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(str1.charAt(i)==str2.charAt(j)){
dp[i][j]=dp[i+1][j+1]+1;
strdp[i][j]=str1.charAt(i)+strdp[i+1][j+1];
}else{
//选右边
if(dp[i][j+1]<dp[i+1][j]){
dp[i][j]=dp[i][j+1]+1;
strdp[i][j]=String.valueOf(str2.charAt(j))+strdp[i][j+1];
}else{
//选下边
dp[i][j]=dp[i+1][j]+1;
strdp[i][j]=String.valueOf(str1.charAt(i))+strdp[i+1][j];
}
}
}
}
return strdp[0][0];
}
}
发现超内存了
优化,不把每个strdp都求出来,只要求最终的即可,通过dp构建最终的字符串。
StringBuilder res = new StringBuilder();
int t1 = 0, t2 = 0;
while (t1 < m && t2 < n) {
if (str1.charAt(t1) == str2.charAt(t2)) {
res.append(str1.charAt(t1));
++t1;
++t2;
} else if (dp[t1 + 1][t2] == dp[t1][t2] - 1) {
res.append(str1.charAt(t1));
++t1;
} else if (dp[t1][t2 + 1] == dp[t1][t2] - 1) {
res.append(str2.charAt(t2));
++t2;
}
}
if (t1 < m) {
res.append(str1.substring(t1));
} else if (t2 < n) {
res.append(str2.substring(t2));
}
return res.toString();