LeetCode:97 交叉字符串(东方财富0807—1)
题目描述:
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true
示例 2:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false
解题思路:
为了实现这个算法, 我们将使用一个 2D 的布尔数组 dp 。dp[i][j] 表示用 s1 的前 (i+1)和 s2 的前 (j+1)个字符,总共 (i+j+2)个字符,是否交错构成 s3 的前缀。为了求出 dp[i][j],我们需要考虑 2 种情况:
- s1 的第 i 个字符和 s2 的第 j个字符都不能匹配 s3 的第 k 个字符,其中 k=i+j+1 。这种情况下,s1 和 s2 的前缀无法交错形成s3 长度为 k+1 的前缀。因此,我们让 dp[i][j]为 False。
- s1 的第 i个字符或者 s2的第 j个字符可以匹配 s3 的第 k 个字符,其中 k=i+j+1。假设匹配的字符是 x且与 s1 的第 i 个字符匹配,我们就需要把 x 放在已经形成的交错字符串的最后一个位置。此时,为了我们必须确保 s1 的前 (i-1) 个字符和 s2 的前 j 个字符能形成 s3 的一个前缀。类似的,如果我们将 s2 的第 j个字符与 s3 的第 k 个字符匹配,我们需要确保 s1 的前 i 个字符和 s2的前 (j-1) 个字符能形成 s3 的一个前缀,我们就让 dp[i][j]为 True。
以下图为例,行数为s1.size()+1,列数为s2.size()+1,
判断上面的dp[i-1][j]是否为T,若是T,则左侧的s1[i-1]是否与s3[i+j-1]的值相同
同理,左侧的dp[i][j-1]是否为T,若是T,则上面的s2[j-1]是否与s3[i+j-1]的值相同
最终得到
复杂度分析
- 时间复杂度:O(m⋅n) 。计算 dp 数组需要 m∗n 的时间。
- 空间复杂度:O(m⋅n)。2 维的 dp 数组需要 (m+1)∗(n+1) 的空间。 m 和 n 分别是 s1 和 s2字符串的长度。
代码:
bool isInterleave(string s1, string s2, string s3) {
int n1 = s1.length();
int n2 = s2.length();
int n3 = s3.length();
if(n3!=n1+n2) //s3长度与s1s2长度之和不等,则s3肯定不能由s1s2交错字符串构成
return false;
bool* flag = new bool[(n1+1)*(n2+1)];//记录dp
memset(flag,0,(n1+1)*(n2+1));//初始化
int cols = n2+1;
for(int i=0;i<=n1;i++)
{
for(int j=0;j<=n2;j++)
{
if(i==0 &&j==0)//第0行第0列
{
flag[i*cols+j]=true;
}else if(i==0) //第0行第1-cols-1列
{
flag[i*cols+j] = (flag[j-1]&&(s2[j-1]==s3[i+j-1]));//左边和上边
}else if(j==0) //第1列第1到rows-1行
{
flag[i*cols+j] = (flag[(i-1)*cols]&&(s1[i-1]==s3[i+j-1])); //上边和左边
}else{ //第1-rows-1行第1-cols-1列
flag[i*cols+j] = (flag[(i-1)*cols+j] && s1[i-1] ==s3[i+j-1]) || (flag[i*cols+j-1] && s2[j-1] == s3[i+j-1]);//上边和左边||左边和上边
}
}
}
return flag[n1*cols+n2];
}