LeetCode 交错字符串
交错字符串(Interleaving String)是一道经典的动态规划问题,在LeetCode上的难度为中等(Medium)。在这篇文章中,我们将学习交错字符串的相关知识,并通过Java代码来完成该问题的解法。
问题描述
给定三个字符串 s1、s2 和 s3,判断 s3 是否由 s1 和 s2 交错组成。换句话说,当从 s1 和 s2 中轮流取字符形成字符串 s3 时,是否存在一种方法,使得 s3 中的字符顺序与 s1 和 s2 中的字符顺序一致。
例如:
输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出: true
解释:
s3 由 s1 和 s2 交错组成,其中 s1 = "aabcc",s2 = "dbbca"。因此,s3 的顺序应该是 "aabbdbccaca",我们可以轮流从 s1 和 s2 中取字符得到。
思路分析
因为 s3 的字符顺序需要和 s1、s2 中的字符顺序一致,所以在验证是否是交错字符串时,我们需要在 s1 和 s2 中轮流取出字符,然后根据顺序组合成 s3。如果 s1 和 s2 的字符顺序无法组合成 s3,那么 s3 就不是交错字符串。
我们可以使用动态规划的思想来解决这个问题。首先要明确的是,只有当 s3 的长度与 s1 和 s2 的长度之和相等时,才有可能是交错字符串。例如,当 s1 = "aabcc"、s2 = "dbbca" 时,若 s3 的长度为 8,那么 s3 就不可能由 s1 和 s2 交错组成。
假设 s1 的长度为 m,s2 的长度为 n,那么 s3 的长度为 m + n。我们使用一个二维数组 dp 来保存 s1 和 s2 的字符在 s3 中的位置信息。例如,当 dp[i][j] = k 时,表示 s3[0, k) 是 s1[0, i) 和 s2[0, j) 的交错组成,其中 0 <= i <= m,0 <= j <= n。
在动态规划的转移过程中,我们需要同时考虑 s1 和 s2 中下一个字符是否能组成 s3 的下一个字符。具体地,当 s1[i-1] == s3[i+j-1] 时,s1[i-1] 可以被加入到 s3 中,此时 dp[i][j] = dp[i-1][j] + 1;同样地,当 s2[j-1] == s3[i+j-1] 时,s2[j-1] 可以被加入到 s3 中,此时 dp[i][j] = dp[i][j-1] + 1。
最终,如果 dp[m][n] = m + n,那么 s3 就是 s1 和 s2 的交错组成,返回 true;否则,返回 false。
示例代码
根据以上思路,我们可以编写出如下的Java代码,以解决交错字符串问题:
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if (s1.length() +s2.length()!=s3.length()) return false;//长度不相等时返回false
boolean[][] dp = new boolean[s1.length()+1][s2.length()+1];
dp[0][0] = true;
for (int i = 0; i <= s1.length(); i++){
for(int j = 0; j <= s2.length(); j++){
//都不为空时的计算
if(i>0 && dp[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)){
dp[i][j] = true;
}
if(j>0 && dp[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1)){
dp[i][j] = true;
}
}
}
return dp[s1.length()][s2.length()];
}
}
运行结果
我们以 s1 = "aabcc"、s2 = "dbbca"、s3 = "aadbbcbcac" 为例,来验证一下以上代码的运行结果。
Solution solution = new Solution();
boolean result = solution.isInterleave("aabcc", "dbbca", "aadbbcbcac");
System.out.println(result);
输出结果为:
true
这表明 s3 = "aadbbcbcac" 是由 s1 = "aabcc" 和 s2 = "dbbca" 交错组成的。
总结
交错字符串是一个比较经