题目描述:
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true
示例 2:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false
解题思路
动态规划
设f[i][j]表示s1的前i个字符和s2的前j个字符能否组成s3的前i+j个字符
如果s3[i+j-1]的最后一个字符为s1的字符
则 f[i][j]=f[i-1][j]&&s3[i+j-1]==s1[i-1]
如果s3[i+j-1]的最后一个字符为s2的字符
则 f[i][j]=f[i][j-1]&&s3[i+j-1]==s2[j-1]
转移方程
f[i][j]=f[i-1][j]&&s3[i+j-1]==s1[i-1] or f[i][j]=f[i][j-1]&&s3[i+j-1]==s2[j-1]
初始条件:f[0][0]=true
代码
bool isInterleave(string s1, string s2, string s3) {
int len1=s1.length();
int len2=s2.length();
int len3=s3.length();
//如果s1的长度与s2的长度相加不等于s3,那么s1和s2一定不能组成s3
if(len1+len2!=len3)
return 0;
vector<vector<int>> f(len1+1,vector<int>(len2+1));
f[0][0]=true;
for(int i=0;i<=len1;i++)
{
for(int j=0;j<=len2;j++)
{
int p=i+j-1;
if(i>0)
f[i][j]|=(f[i-1][j]&&s3[p]==s1[i-1]);
if(j>0)
f[i][j]|=(f[i][j-1]&&s3[p]==s2[j-1]);
}
}
return f[len1][len2];
}
解法二
记录组成s3前i个字符所需要的s1的字符数j,用数组record记录
求s3前i+1个字符所需要的s1的字符数步骤:
遍历数组record,tmp表示数字
如果s1[tmp]==s3[i+1],表示s3的前i+j个字符所需的s1的字符数为tmp+1,则将tmp+1放入record中
如果s2[i+1-tmp-1]=s3[i+1],表示s3的前i+j个字符所需的s1的字符数为tmp,则将tmp放入record中
如果遍历过程中record为空,则表示s3不能由s1和s2组成,返回false
bool isInterleave(string s1, string s2, string s3)
{
//记录所需的s1的字符数
vector<int> record;
int len1=s1.length();
int len2=s2.length();
int len3=s3.length();
if(len1+len2!=len3)
return 0;
//第一个字符验证
int j=0;
if(s1[j]==s3[j])
record.push_back(j+1);
if(s2[j]==s3[j])
record.push_back(j);
for(int i=2;i<=len3;i++)
{
if(record.size()==0)
return 0;
vector<int> record2;
while(!record.empty())
{
int tmp=record.back();
record.pop_back();
if(tmp<len1&&s1[tmp]==s3[i-1])
record2.push_back(tmp+1);
if(i-tmp-1<len2&&s2[i-tmp-1]==s3[i-1])
record2.push_back(tmp);
}
//record去重
set<int>s(record2.begin(), record2.end());
record.assign(s.begin(),s.end());
}
if(record.size()==0)
return 0;
return 1;
}