给出两个字符串 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 都由小写英文字母组成。
解题思路:
设dp[i + 1][j + 1]为str1[0 , i] 和str2[0 , j]的最短公共超序列 的长度;
当str1[i] == str2[j]时,dp[i + 1][j + 1] = dp[i][j] + 1 ;
当str1[i] != str2[j]时, 判断谁是最短公共超序列的最后一个字符,如果是str1[i],那么dp[i + 1][j + 1] = dp[i][j + 1] + 1 ;
如果是str2[j] , 那么dp[i + 1][j + 1] = dp[i + 1][j ] + 1 ;
然后根据dp[i+1][j + 1]的关系,逆序将字符连接到res中;
class Solution {
public:
string shortestCommonSupersequence(string str1, string str2)
{
int n1 = str1.size() , n2 = str2.size() ;
vector> dp(n1 + 1 , vector(n2 + 1, 0)) ;
for(int j = 0 ; j < n2 ; ++j) dp[0][j + 1] = dp[0][j] + 1 ;
for(int i = 0 ; i < n1 ; ++i) dp[i + 1][0] = dp[i][0] + 1 ;
for(int i = 0 ; i < n1 ; ++i)
for(int j = 0 ; j < n2 ; ++j)
{
if(str1[i] == str2[j]) dp[i + 1][j + 1] = dp[i][j] + 1 ;
else dp[i + 1][j + 1] = min(dp[i][j + 1] , dp[i + 1][j]) + 1;
}
int i = n1 - 1 , j = n2 - 1 ;
string res ;
while(i >= 0 && j >= 0)
{
if(str1[i] == str2[j])
{
res += str1[i] ;
i-- ;
j-- ;
}
else if(dp[i + 1][j + 1] == dp[i][j + 1] + 1)
{
res += str1[i] ;
i-- ;
}
else
{
res += str2[j] ;
j-- ;
}
}
if(i < 0)
{
while(j >= 0)
{
res += str2[j] ;
j-- ;
}
}
else
{
while(i >= 0)
{
res += str1[i] ;
i-- ;
}
}
reverse(res.begin() , res.end()) ;
return res ;
}
};