题目:
给出两个字符串 str1 和 str2,返回同时以 str1 和 str2 作为子序列的最短字符串
如果答案不止一个,则可以返回满足条件的任意一个答案
思路:
先找到两字符串的最长公共子序列,再用双指针倒序遍历两字符串,构造最短公共超序列
第一步:求最长公共子序列
定义f[i][j]:字符串str1的前i个字符和str2的前j个字符的最长公共子序列长度
- 如果str1[i]==str2[j],则i存在,j存在,f[i][j]=f[i-1][j-1]+1
- 否则f[i][j] = max(f[i-1][j],f[i][j-1])
详细过程见:【蓝桥杯集训26】线性DP(4 / 4)_Roye_ack的博客-CSDN博客
第二步:在最长公共子序列基础上构造答案
str1: a b a c str2: c a b ans: c a b a c
class Solution {
public String shortestCommonSupersequence(String str1, String str2) {
int m=str1.length(),n=str2.length();
int[][] f=new int[m+1][n+1];
//定义f[i][j]:str1的前i个字符和str2的前j个字符的最长公共子序列
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
if(str1.charAt(i-1)==str2.charAt(j-1)) //如果第i个字符和第j个字符都在
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 res=new StringBuilder();
while(i>0||j>0)
{
//如果某一字符串遍历完 则将剩下字符串加入答案
if(i==0) res.append(str2.charAt(--j));
else if(j==0) res.append(str1.charAt(--i));
else
{
if(f[i][j]==f[i-1][j]) //最长序列必然没有str1[i-1]
res.append(str1.charAt(--i));
else if(f[i][j]==f[i][j-1]) //最长序列必然没有str2[j-1]
res.append(str2.charAt(--j));
else
{
res.append(str1.charAt(--i));
--j;
}
}
}
return res.reverse().toString();
}
}