LeetCode—97. Interleaving String
题目
https://leetcode.com/problems/interleaving-string/description/
给3个字符串,判断其中两个s1和s2是否可以不变顺序的交叉组合形成s3.
思路及解法
动态规划的题目。
考虑递推公式。假设使用二维数组dp[i][j]表示s3的前i+j个字符是否可以由s1的前i个字符和s2的前j个字符组合表示,那么递推公式是一个什么情况呢?我们想dp[i][j]可以由哪几种情况而来呢?对于s3的第i+j-1个字符,我们可以有两种选择:要么选s1的第i-1个字符,要么选s2的第j-1个字符,所以递推公式就是:
dp[i][j] = (dp[i][j - 1] && s2[j - 1] == s3[i + j - 1]) || (dp[i - 1][j] && s1[i - 1] == s3[i + j - 1])
这样,最终我们只要得到dp[s1_len][s2_len]的值就是最后的结果了。
因为是一个二维的动态规划,所以时间复杂度是O(m*n),m和n分别是s1和s2的长度。空间花费,可以看出递推式中只需要用到上一行的信息,所以我们只需要一个一维数组就可以完成历史信息的维护,为了更加优化,我们把短的字符串放在内层循环,这样就可以只需要短字符串的长度即可,所以复杂度是O(min(m,n))。
再者就是边界条件了。我们先看下面的图:
边界条件就是要初始化黑框的第一行和第一列,根据上面得到的递推公式,我们只需要将i和j分别置0就可以得到边界条件了。
代码
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
int s1_len = s1.length();
int s2_len = s2.length();
int s3_len = s3.length();
if(s3_len != s1_len+s2_len) return false;
boolean[][] dp = new boolean[s1_len+1][s2_len+1];
dp[0][0] = true;
for(int i=1; i<=s1_len; i++){
dp[i][0] = dp[i-1][0] && (s1.charAt(i-1)==s3.charAt(i-1));
}
for(int j=1; j<=s2_len; j++){
dp[0][j] = dp[0][j-1] && (s2.charAt(j-1)==s3.charAt(j-1));
}
for(int i=1; i<=s1_len; i++){
for(int j=1; j<=s2_len; j++){
dp[i][j] = (dp[i][j-1]&&(s2.charAt(j-1)==s3.charAt(i+j-1))) || (dp[i-1][j]&&(s1.charAt(i-1)==s3.charAt(i+j-1)));
}
}
return dp[s1_len][s2_len];
}
}