「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
题目:
给定三个字符串 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
——————————————————————————————————————————
思路:
用三个指针,分别扫描 s1 s2 s3,如下图左例,i、k 指向的字母相同,则选择 s1[i]s1[i] 作为 s3[k]s3[k],i、k 都右移一位,递归剩余子串。
如果 k 最后越界,代表 s3 选完了,成功从 s1 和 s2 中交错选出字母组成自己。
i、j、k 指向相同的字母,选哪个?我们试着选 s1,让指针 i、k 右移,往下递归,如果不能返回 true,说明这个分支得不到 true 的结果,把右移的 i 和 k 撤销回来,改将 j 和 k 右移,向下递归。
下面代码将使用isValid判断这个情况
这就是回溯,试探性地穷举,如果发现当前选择不是问题的解,就撤销当前选择,回到之前的状态,进入另一个分支,继续寻找问题的解
代码
//普通的dfs
const isInterleave = (s1, s2, s3) => {
if (s1.length + s2.length != s3.length) return false;
const check = (i, j, k) => { // 检查ijk开始的子串是否满足题目条件
// k越界,s3扫描完了,返回true
if (k == s3.length) return true;
let isValid = false;
// i指针没有越界,且s1[i]和s3[k]相同
if (i < s1.length && s1[i] == s3[k]) {
isValid = check(i + 1, j, k + 1); // i、k右移一位,递归考察
}
// j 指针没有越界,且s2[i]和s3[k]相同
if (j < s2.length && s2[j] == s3[k]) {
isValid = isValid || check(i, j + 1, k + 1);
// 重点: 有可能i、j、k指向相同的字符,尝试 i、k 右移,但已经做过了
// isValid 就是 check(i + 1, j, k + 1) 的结果
// 如果它为true,就不用执行 j、k 右移的递归,如果是false,执行递归
}
return isValid; // 整个遍历过程都没有返回true,则返回默认的false
};
return check(0, 0, 0);
};
// 动态规划
const isInterleave = (s1, s2, s3) => {
if (s1.length + s2.length != s3.length) return false;
//创建二维数组
const memo = new Array(s1.length + 1).fill('').map(item => new Array(s2.length + 1))
// const memo = new Array(s1.length + 1);
// for (let i = 0; i < memo.length; i++) {
// memo[i] = new Array(s2.length + 1);
// }
const check = (i, j, k) => {
if (memo[i][j] != null) return memo[i][j];
if (k == s3.length) return memo[i][j] = true;
let isValid = false;
if (i < s1.length && s1[i] == s3[k]) {
isValid = check(i + 1, j, k + 1);
}
if (j < s2.length && s2[j] == s3[k]) {
isValid = isValid || check(i, j + 1, k + 1);
}
return memo[i][j] = isValid;
};
return check(0, 0, 0);
};