问题描述
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true
示例 2:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false
解题思路
这个题可以用动态规划解决,思路与LCS(longest common subsequence,最长公共子序列)类似。用 d p [ i ] [ j ] dp[i][j] dp[i][j] 来记录 s 1 [ : i ] , s 2 [ : j ] s1[:i], s2[:j] s1[:i],s2[:j]是否可以交错着组成 s 3 [ : i + j ] s3[:i+j] s3[:i+j]。注意,此处的index是 “up to but not included”,例如 s [ : i ] s[:i] s[:i]就是从开头选取该 string s长度为 i。
下一步就是写出状态转移方程,设想,如果我们要考察 s 1 [ : i ] , s 2 [ : j ] s1[:i], s2[:j] s1[:i],s2[:j]是否可以交错着组成 s 3 [ : i + j ] s3[:i+j] s3[:i+j],只需要查看:
- 是否 s 1 [ i − 1 ] = = s 3 [ i + j − 1 ] s1[i-1]==s3[i+j-1] s1[i−1]==s3[i+j−1] 如果确实为真,则问题可以被 reduce到考察 s 1 [ : i − 1 ] , s 2 [ : j ] s1[:i-1], s2[:j] s1[:i−1],s2[:j]是否可以交错着组成 s 3 [ : i + j − 1 ] s3[:i+j-1] s3[:i+j−1],其实就是 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]的值,这就完成了问题的转换。
- 类似的,我们还可以考察是否 s 2 [ j − 1 ] = = s 3 [ i + j − 1 ] s2[j-1]==s3[i+j-1] s2[j−1]==s3[i+j−1] 如果确实为真,则问题可以被 reduce到考察 s 1 [ : i ] , s 2 [ : j − 1 ] s1[:i], s2[:j-1] s1[:i],s2[:j−1]是否可以交错着组成 s 3 [ : i + j − 1 ] s3[:i+j-1] s3[:i+j−1],其实就是 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]的值。
综上,
dp[i][j] = (dp[i-1][j] * (s1[i-1]==s3[i+j-1])) || (dp[i][j-1] * (s2[j-1]==s3[i+j-1]));
总的来说,可以写出如下代码:
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int m = s1.size(), n = s2.size();
if (m+n != s3.size()) return false;
if (m==0) return s3 == s2;
if (n==0) return s3 == s1;
dp[i][j] is true if s1[:i] and s2[:j] interleaves s3[:i+j]
indexes are "up to but not included"
vector< vector<int> > dp(m+1, vector<int>(n+1, 0));
// initialize dp
dp[0][0] = 1;
for (int i=1; i<=m; i++) {
if (s1[i-1] == s3[i-1] ) dp[i][0] = dp[i-1][0];
}
for (int j=1; j<=n; j++) {
if (s2[j-1] == s3[j-1] ) dp[0][j] = dp[0][j-1];
}
for (int i=1; i<=m; i++) {
for (int j=1; j<=n; j++){
dp[i][j] = (dp[i-1][j] * (s1[i-1]==s3[i+j-1])) || (dp[i][j-1] * (s2[j-1]==s3[i+j-1]));
}
}
return dp[m][n];
};
时间击败 90%,空间击败100%
进一步思考:使用 1D dp
如果我们再想一想状态转移方程,我们会发现,它其实只依赖于上方和左方的值,这提示我们其实可以使用一个 1D dp array就可以实现了。
具体代码如下:
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int m = s1.size(), n = s2.size();
if (m+n != s3.size()) return false;
if (m==0) return s3 == s2;
if (n==0) return s3 == s1;
vector<int> dp(n+1, 0);
dp[0] = 1;
for (int j=1; j<=n; j++) {
if (s2[j-1] == s3[j-1] ) dp[j] = dp[j-1];
}
for (int i=1; i<=m; i++){
for (int j=0; j<=n; j++){
if (j==0) dp[j] = dp[j] * (s1[i-1] == s3[i-1]);
else dp[j] = (dp[j] * (s1[i-1]==s3[i+j-1])) || (dp[j-1] * (s2[j-1]==s3[i+j-1]));
}
}
return dp[n];
}
};
动态规划嘛,就是如果想出了dp和状态转移就简单得跟什么似的,想不出就抓破脑袋…
参考
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/interleaving-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。