携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
题目
给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。
两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:
- s = s1 + s2 + ... + sn
- t = t1 + t2 + ... + tm
- |n - m| <= 1
- 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + ... 或者 t1 + s1 + t2 + s2 + t3 + s3 + ...
注意:a + b 意味着字符串 a 和 b 连接。
示例 1
输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出:true
示例 2
输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出:false
示例 3
输入:s1 = "", s2 = "", s3 = ""
输出:true
提示
0 <= s1.length, s2.length <= 1000 <= s3.length <= 200s1、s2、和s3都由小写英文字母组成
题解
思路
我们可以直接使用动态规划尝试填充 s3,常见的思路为使用二维数组 bool[len1][len2] dp;
其中dp[i][j]表示 s1 的前 i 个字符和 s2 的前 i 个字符是否可以交错组成 s3 的前 i+j 个字符
该方法需要注意的两个点为:
dp[0][0]一定为 true,因为 0 个字符和 0 个字符一起组成 s3 的前 0 个字符,一定是 true 的
需要首先初始化一下 dp[0][j],因为有可能出现 s1 为空字符的情况
状态转移方程为: dp[i][j] = s3[i+j-1] == s1[i-1] && dp[i-1][j] || s3[i+j-1] == s2[j-1] && dp[i][j-1]
在理解该思路后,也可以将动态规划辅助数组优化至一维
此时:
我们可以将二维的辅助数组优化为一维: dp[i] 表示 s2 的前 j 个字符能够和 s1 当前的前 i 个字符组成 s3 的前 (i+j) 个字符
每次外层循环时,我们需要尝试更新 dp[0],因为现在的 dp[0] 是 dp[i][0],因此 dp[0] 需要= s1[i-1] == s3[i-1] && dp[0]
内层循环时无需任何变化,因为只要我们按 j 递增的方向遍历 j,则在 j 到达j时,dp[j] 确实为dp[i-1][j],而 dp[j-1] 被更新为 dp[i][j-1]
代码
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int len1 = s1.length(), len2 = s2.length();
if (s3.length() != len1 + len2) return false;
vector<bool> dp(len2 + 1);
dp[0] = true;
for (int i = 1; i <= len2 && dp[i-1]; ++i)
dp[i] = s3[i-1] == s2[i-1];
for (int i = 1; i <= len1; ++i)
{
dp[0] = dp[0] && s1[i-1] == s3[i-1];
for (int j = 1; j <= len2; ++j)
{
dp[j] = dp[j] && s1[i-1] == s3[i+j-1] || dp[j-1] && s2[j-1] == s3[i+j-1];
}
}
return dp[len2];
}
};
结语
业精于勤,荒于嬉;行成于思,毁于随。