题目
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例1
输入:
s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出:
true
示例2
输入:
s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出:
false
解法
- 一看就是个动态规划,但是动态转移不好弄
- dp[i][j] 代表s1的前i个字符和s2的前j个字符能否组成s3的前i+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])
dp数组
0 1 2 3 4 5
s2 d b b c a
0 s1 1 0 0 0 0 0
1 a 1 0 0 0 0 0
2 a 1 1 1 1 1 0
3 b 0 1 1 0 1 0
4 c 0 0 1 1 1 1
5 c 0 0 0 1 0 1
下标 0 1 2 3 4 5 6 7 8 9
s1: a a b c c
s2: d b b c a
s3: a a d b b c b c a c
第一个字符
- 可以和s1的第一个字符匹配
dp[1][0] = dp[0][0]&&s1[1-1]==s3[1+0-1] = 1 - 可以和s2的第一个字符匹配
dp[0][1] = dp[0][0]&&s2[1-1]==s3[1+0-1] = 0
两个字符可能的情况dp[2][0],dp[1][1],dp[0][2]
- dp[2][0] 代表 s3的2个字符都和s1匹配
先判断s3的第1个字符是否和s1的第1个字符匹配,再判断s3的第2个字符(下标为1)是否和s1的第2个字符(下标为1)相等 - dp[1][1]代表 s3的2个字符各和s1的1个和s2的1个匹配
- 先判断dp[0][1],如果dp[0][1]=1说明s3的第1个字符是和s2的第1个字符匹配,再判断s1的第1个字符(下标为0)和s3的第1个字符(下标为0)是否相等
- 先判断dp[1][0],如果dp[1][0]=1说明s3的第1个字符是和s1的第1个字符匹配,再判断s2的第1个字符和s3的第1个字符是否相等
- dp[0][2]代表 s3的2个字符都和s2匹配
先判断s3的第1个字符是否和s2的第1个字符匹配,再判断s3的第2个字符(下标为1)是否和s2的第2个字符(下标为1)相等
dp[3][2]也就是s3的前5个字符,是否能由s1的前3个字符和s2的前两个组成
- 先判断dp[2][2](s3的前4个字符是否能由s1的前2个字符和s2的前两个组成),如果能组成判断s1的第3个字符(下标为2)是否和s3的第5个字符(下标为4)
dp[3][2] = dp[2][2]&&s1[3-1]==s3[3+2-1] - 先判断dp[3][1](s3的前4个字符是否能由s1的前3个字符和s1的前两个组成),如果能组成判断s2的第2个字符(下标为1)是否和s3的第5个字符(下标为4)
dp[3][2] = dp[3][2]&&s2[2-1]==s3[3+2-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])
代码
简单版本
#include <stdio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <math.h>
using namespace std;
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int m = s1.size();
int n = s2.size();
int r = s3.size();
vector<vector<int> > dp(m+1,vector<int> (n+1,0));
dp[0][0] = 1;
//如果s1和s2加起来的长度都和s3的长度都不一样,false
if(m+n!=r)
return false;
//循环遍历
for (int i = 0; i <= m; i++) {
for (int j = 0; j <=n; j++) {
int p = i + j - 1;//注意下标
if (i > 0) {//注意下标不能等于0,后面要减一
dp[i][j] |=(dp[i - 1][j] && s1[i - 1] == s3[p]);//注意下标
}
if (j > 0) {
dp[i][j] |= (dp[i][j - 1] && s2[j - 1] == s3[p]);
}
}
}
return dp[m][n];
}
};
int main()
{
string s1 = "aabcc";
string s2 = "dbbca";
string s3 = "aadbbcbcac";
Solution s;
cout<<s.isInterleave(s1, s2, s3);
}
优化空间复杂度,滚动数组
#include <stdio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <math.h>
using namespace std;
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int m = s1.size();
int n = s2.size();
int r = s3.size();
vector<int> dp(n+1,0);
dp[0]= 1;
if(m+n!=r)
return false;
//dp只和上一次的数值有关,二维数组可压缩成一维
for (int i = 0; i <= m; i++) {
for (int j = 0; j <=n; j++) {
int p = i + j - 1;
if (i > 0) {
dp[j] &= s1[i - 1] == s3[p];
}
if (j > 0) {
dp[j] |= (dp[j - 1] && s2[j - 1] == s3[p]);
}
}
}
return dp[n];
}
};
int main()
{
string s1 = "aabcc";
string s2 = "dbbca";
string s3 = "aadbbcbcac";
Solution s;
cout<<s.isInterleave(s1, s2, s3);
}
今天也是爱zz的一天哦!