版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013033845/article/details/52315001
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.
这题一开始没有想清楚它是想干嘛,于是写了一个LCS,判断s1和s3以及s2和s3是否相等。
但是显然这样的不正确的。因为对于用例
"aa" "ab" "aaba"
显然就发现了错误,因为存在一个先后顺序的问题,所以这个很像一个递归来解决问题的问题。
事实上递归确实是一种正确的解法,但是会超时。
这道题的DP思路比较难想,但是看了题解觉得和LCS的DP方程还真是非常之像。
首先定义状态:
以dp[i][j]表示s1的前i个字符、s2的前j个字符可以匹配s3的前i+j个字符,初始化如下:
对于字符串aadbbcbcac进行判定
初始化:一个字符串为空的时候,可以匹配到哪一位,显然只需要判断从第一位开始依次与s3匹配
第一步:ad是否匹配aa => F , aad是否匹配aad => T ...
第二部:adb是否匹配aad =>F ...
...
我们发现其实和LCS的递推非常之类似,只不过是将两个字符串与第三方比较。
由矩阵推导得出规律:
确实咋一看很难想出来的,慢慢积累经验吧。
bool isInterleave(string s1, string s2, string s3) {
int m=s1.size();
int n=s2.size();
bool dp[m+1][n+1];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=m;i++){
if(s3[i-1]==s1[i-1])
dp[i][0]=1;
else break;
}
for(int i=1;i<=n;i++){
if(s3[i-1]==s1[i-1])
dp[0][i]=1;
else break;
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
int k=i+j;
if(s1[i-1]==s3[k-1])
dp[i][j]=dp[i][j] | dp[i-1][j];
if(s2[j-1]==s3[k-1])
dp[i][j]=dp[i][j]|dp[i][j-1];
}
}
return dp[m][n];
}
在这里,也顺便复习一下LCS的代码
感觉自己这样写的有点挫,下次还是把式子推到1~m,1~n好了
int LCS(string s1,string s2){
int m=s1.size();
int n=s2.size();
int dp[m][n];
memset(dp,0,sizeof(dp));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(s1[i]==s2[j]){
if(i>0 && j>0)
dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=1;
}
else{
int v1=i>0?dp[i-1][j]:0;
int v2=j>0?dp[i][j-1]:0;
dp[i][j]=max(v1,v2);
}
}
}
return dp[m-1][n-1];
}