题目
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true
示例 2:
输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false
解答
解法一:递归
代码很容易理解。
主要思想是:s3 当前位置的字符要么来自 s1 , 要么来自 s2 。
递归代码有很多重复运算,必然会导致超时 TLE 。
代码
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if(s3.length() != s1.length() + s2.length()) return false;
if(s3.isEmpty()) return true;
char first = s3.charAt(0);
if(!s1.isEmpty() && first == s1.charAt(0)) {
if(isInterleave(s1.substring(1), s2, s3.substring(1))) return true;
}
if(!s2.isEmpty() && first == s2.charAt(0)) {
if(isInterleave(s1, s2.substring(1), s3.substring(1))) return true;
}
return false;
}
}
结果
使用记忆化搜索可以去掉大量重复的计算。
记忆化搜索代码
class Solution {
// memo[i][j] 表示:s3[0 .. i + j - 1] 是否 s1[0 ... i - 1] 与 s2[0 ... j - 1] 的交错串
private Boolean[][] memo;
public boolean isInterleave(String s1, String s2, String s3) {
memo = new Boolean[s1.length() + 1][s2.length() + 1];
return isInterleave(s1.toCharArray(), s1.length(), s2.toCharArray(), s2.length(), s3.toCharArray(), s3.length());
}
private boolean isInterleave(char[] w1, int i, char[] w2, int j, char[] w3, int k) {
if(memo[i][j] != null) return memo[i][j];
boolean ret = false;
if(k != i + j) {
ret = false;
} else if(k == 0) {
ret = true;
} else {
if(i != 0 && w1[i - 1] == w3[k - 1] && isInterleave(w1, i - 1, w2, j, w3, k - 1)) ret = true;
if(j != 0 && w2[j - 1] == w3[k - 1] && isInterleave(w1, i, w2, j - 1, w3, k - 1)) ret = true;
}
memo[i][j] = ret;
return ret;
}
}
结果
解法二:动态规划
动态规划四要素:
-
状态定义:dp[i][j] 表示 s1[0 … i - 1] 与 s2[0 … j - 1] 是否能形成交错字符串 s3[0 … i + j - 1]。
-
状态转移:dp[i][j] = (dp[i - 1][j] && s1 与 s3 当前字符是否匹配) || (dp[i][j - 1] && s2 与 s3 当前字符是否匹配);
-
状态初始化:dp[0][0] = true 。
-
结果:dp[s1.length()][s2.length()]
复杂度:O(nm) 时间,O(nm) 空间。(tips:空间可以优化)
代码
public class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if (s3.length() != s1.length() + s2.length()) return false;
boolean dp[][] = new boolean[s1.length() + 1][s2.length() + 1];
for (int i = 0; i <= s1.length(); i ++) {
for (int j = 0; j <= s2.length(); j ++) {
if (i == 0 && j == 0) {
dp[i][j] = true;
} else if (i == 0) {
dp[i][j] = dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
} else if (j == 0) {
dp[i][j] = dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1);
} else {
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[s1.length()][s2.length()];
}
}