https://oj.leetcode.com/problems/interleaving-string/
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc",
s2 = "dbbca",
When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
public boolean isInterleave(String s1, String s2, String s3)
其实如果你们是按顺序做一路做到这里,看到这样的题目第一反应大概就是DP题了。这一题在OJ里面属于比较简单的DP题。整个推导式都比较容易思考。其实我一直在想DP的推导式怎么才能弄出来,是不是有规律可循?其实也不尽然,当你懂的一些DP的基本规律,剩下的都是积累题目数量而产生的感觉。当然,一些比较高级的DP概念还有待我们继续学习。。譬如插头DP什么的,真是搞不懂。。
这题的概念其实也是很清晰的,就是给定两个index,i和j分别表示我们跑到了s1和s2的什么地方了。然后看看是否能s3的i + j那一点配对,能的话就OK往下走,不能的话那就对不起了,你就只能走到这里了。基于这个简单的概念,我们可以得到推导式如下
f(i, j) = s1[i] == s3[i + j] && f(i - 1, j) || s2[j] == s3[i +j] && f(i, j - 1)
base case大家自己想吧。其实也不难想。
按照国际惯例,首先放出来的是一则暴力递归外加截枝,可以AC的代码段。
public boolean isInterleave(String s1, String s2, String s3) {
if(s3.length() != s1.length() + s2.length())
return false;
byte[][] cached = new byte[s1.length() + 1][s2.length() + 1]; //用来截枝,0表示没走过,1表示true,-1表示false
return helper(s1, s2, s3, cached, 0, 0);
}
public boolean helper(String s1, String s2, String s3, byte[][] cached, int i, int j){
if(i == s1.length() && j == s2.length())
return true;
if(cached[i][j] != 0)//截枝部分,注意我的做法是bottom-top,这一题你 top-bottom是没办法截枝的了。
return cached[i][j] == 1 ? true : false;
boolean res = false;
if(i != s1.length() && s1.charAt(i) == s3.charAt(i + j))
res |= helper(s1, s2, s3, cached, i + 1, j);
if(!res && j != s2.length() && s2.charAt(j) == s3.charAt(i + j))//!res这个判断算一个小截枝,如果上面一步已经成功了,就没必要验证这里了。
res |= helper(s1, s2, s3, cached, i, j + 1);
cached[i][j] = res ? (byte)1 : (byte)-1;
return res;
}
再来就是dp解了:
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];
dp[0][0] = true;//base case,空子串和空子串弄起来那肯定也是空子串....
for(int i = 0; i < s1.length(); i++){
dp[i + 1][0] = dp[i][0] && s1.charAt(i) == s3.charAt(i);
}
for(int i = 0; i < s2.length(); i++){
dp[0][i + 1] = dp[0][i] && s2.charAt(i) == s3.charAt(i);
}
for(int i = 1; i <= s1.length(); i++){
for(int j = 1; j <= s2.length(); 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[s1.length()][s2.length()];
}
正如之前的dp题一样,这一题可以将空间化为一维。大家就自己根据我的代码看看怎么化简了。最近懒了,懒得再写一个一维的代码了。