题目描述:
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc"
,
s2 = "dbbca"
,
When s3 = "aadbbcbcac"
, return true.
When s3 = "aadbbbaccc"
, return false.
那么状态式定义为:
f[ k ] [ i ] [ j ] = ( f [ k-1 ] [i ] [ j - 1] && s2[ j-1] == s3 [ k -1] // s2的第j-1个字符与s3的第k-1个字符匹配。
或者是 = ( f [ k-1 ] [ i-1 ] [ j ] && s1 [ i-1] == s3 [ k -1] // s1的第i-1个字符与s3的第k-1个字符匹配。
两者只要有一个满足条件即可。
代码如下:
Version 1: 时间复杂度 O(n^3),空间复杂度 O(n^3).Time : ~200ms
bool isInterleave(string s1, string s2, string s3) {
const int n1 = s1.size(), n2= s2.size(), n3 = s3.size();
if(n1==0) return s2==s3;
if(n2==0) return s1==s3;
bool f[n3+1][n1+1][n2+1];
fill_n(&f[0][0][0], (n3+1)*(n1+1)*(n2+1),false);
f[0][0][0]=true;
//k i j !!
//i==0
for(int j = 1 ; j <= n2;++j)
{
f[j][0][j] = f[j-1][0][j-1] && s2[j-1]==s3[j-1];
}
//j==0
for(int i = 1 ; i <= n1;++i)
{
f[i][i][0] = f[i-1][i-1][0] && s1[i-1]==s3[i-1];
}
for(int k=1;k<=n3;++k)
{
for(int i=1;i<=n1;++i)
{
for(int j=1;j<=n2;++j)
{
f[k][i][j] = (f[k-1][i-1][j] && s1[i-1]==s3[k-1]) || (f[k-1][i][j-1] && s2[j-1]==s3[k-1]);
}
}
}
return f[n3][n1][n2];
}
Version 2: 时间复杂度 O(n^2),空间复杂度 O(n^2).Time :~ 4ms
bool isInterleave(string s1, string s2, string s3) {
const int n1 = s1.size(), n2= s2.size(), n3 = s3.size();
if(n1 + n2 < n3) return false;
if(n1==0) return s2==s3;
if(n2==0) return s1==s3;
bool f[n1+1][n2+1];
fill_n(&f[0][0], (n1+1)*(n2+1), false);
//initialize
f[0][0] = true;
//n1.size() <= n3.size() ,否则在前面就自动return false.
for(int i = 1; i < n1+1; ++i)
//f[i][0] = (s1.substr(0,i) == s3.substr(0,i));
f[i][0] = f[i-1][0] && s1[i-1] == s3[i-1];
for(int j = 1; j< n2+1; ++j)
//f[0][j] = (s2.substr(0,j) == s3.substr(0,j));
f[0][j] = f[0][j-1] && s2[j-1] == s3[j-1];
for(int i = 1; i <= n1;++i)
for(int j=1;j<=n2;++j)
f[i][j] = ((f[i-1][j] && s1[i-1] == s3[i+j-1]) || (f[i][j-1] && s2[j-1] == s3[i+j-1]) );
return f[n1][n2];
}
Version 3: 时间复杂度 O(n^2),空间复杂度 O(n). Time :~ 4ms
使用滚动数组来解决:
bool isInterleave(string s1, string s2, string s3) {
const int n1 = s1.size(), n2= s2.size(), n3 = s3.size();
if(n1 + n2 < n3) return false;
if(n1==0) return s2==s3;
if(n2==0) return s1==s3;
//进一步降低空间复杂度为O(min(n1,n2))
bool f[n1+1];
fill_n(&f[0],n1+1,false);
f[0]=true;
//first row
for(int i = 1 ; i <= n1; ++i)
f[i] = f[i-1]&&(s1[i-1]==s3[i-1]); //never out of range!! for n1 <= n3
//column 0 has completed
//n2 cycles
for(int times = 1; times <= n2; ++times)
{
//update row
//specially process the first element
f[0] = (s2[times-1] == s3[times-1] && f[0]);
for(int i = 1;i <= n1;++i)
{
f[i] = ( f[i] && s2[times-1]==s3[i+times-1]) || (f[i-1] && s1[i-1]==s3[i+times-1]);
}
}
return f[n1];
}