「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
前言
力扣第九十七题 交错字符串
如下所示:
给定三个字符串 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
复制代码
一、思路
题目的意思很清楚,就是:**判断 s1
中若干的子串与 s2
中若干的子串组合,是否能构成 s3
**
很明显要满足以下的条件:
s1.len + s2.len == s3.len
:s1
和s2
的长度相加要等于s3
的长度s1
和s2
的字符个数要与s3
中的字符个数相等
我们不妨假设 s1
中 1 ~ i
可以与 s2
中的 1 ~ j
构成交错字符串,如下图所示:
注意:这里的
i
和j
是指元素的位置(或个数)从1
开始,并不为数组中的下标
如果此时 s3
中第 i+j+1
这个元素为 c
,请问 s1
或 s2
添加什么元素可以再使:
s1
中1 ~ i+1
和s2
中的1 ~j
构成交错字符串s3 (1 ~ i+j+1)
- 或
s1
中1 ~ i
和s2
中的1 ~j+1
构成交错字符串s3 (1 ~ i+j+1)
呢?
其实答案很明显:就是在 s1
的末尾叫上 c
或 s2
的末尾加上 c
即可,如下图所示:
通过上面的推理我们发现 s1
的 1~i
个字符与 s2
的 1~j
个字符是否构成交错字符,是根据他们各自的子串 1~i-1
和 1~j
、1~i
和 1~j-1
是否构成交错字符有关。这就与动态规划的思想不谋而合了。
假设 dp[i][j]
为 s1
中的 1~i
和 s2
中的 1~j
是否构成交错字符,根据上面的推理,我们很容易就可以得到状态转移方程:
dp[i][j] = (dp[i-1][j] && s1[i] == s3[i+j]) || (dp[i][j-1] && s2[j] == s3[i+j])
既然有了思路,那么实现代码就是一个自底向上的过程了。
二、实现
实现代码
我们要在遍历前,先初始化边界值
public boolean isInterleave(String s1, String s2, String s3) {
int len1 = s1.length();
int len2 = s2.length();
int len3 = s3.length();
// 如果长度不等,则一定不为交错字符串
if(len1 + len2 != len3)
return false;
boolean[][] dp = new boolean[len1+1][len2+1];
// 初始化边界
dp[0][0] = true;
// 初始化第一列和第一行
for (int i=1; i<=len2; i++) {
dp[0][i] = s2.charAt(i-1) == s3.charAt(i-1) && dp[0][i-1];
}
for (int i=1; i<=len1; i++) {
dp[i][0] = s1.charAt(i-1) == s3.charAt(i-1) && dp[i-1][0];
}
// 根据状态转移方程填充dp即可
for (int i=1; i<=len1; i++) {
for (int j=1; j<=len2; j++) {
dp[i][j] = (dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)) ||
(dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1));
}
}
return dp[len1][len2];
}
复制代码
测试代码
public static void main(String[] args) {
new Number97().isInterleave("db","b", "cbb");
}
复制代码
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~