好题!2D DP问题,两个字符串的比较都逃不出这个套路啊~ 啊哈哈
同类题型:
edit distance, 两个子串的相互比较
interleaving string,两个子串合并成一个串。两个subsequence的合并问题。
distinct subsequence,两个子串的包含关系,也可以堪称是interleaving string的变体,因为短串是长串的一部分,剩下都可以认为是第二个子串。
2D DP 类型,t短s长,以t定array size, A[i+1] 记录的是 index =i 的t中字母的情况。同时进行s.length() 次迭代。A的话要从后往前,base是 A[i+1]= A[i+1], bonus是 t.i == s.j 时,还有额外的A[i]
class Solution {
public int numDistinct(String s, String t) {
if(t.length()==0) return 1; // t is shorter
if(s.length()==0) return 0; // s is longer
int[] res = new int[t.length()+1]; // t 是target
res[0] = 1;
for(int i=0;i<s.length();i++){ // 要对s的每一个字母都进行检查。
for(int j=t.length()-1;j>=0;j--){ // !!!从t的后面开始,j是index,代表string中字母实际的index
//实际上是被记录在res[j+1]中,这也是为什么res的长度多1
//在res[0]的位置,其实就是 dp 转换方程开始时 所需要的 initial value
res[j+1] = (s.charAt(i)==t.charAt(j)?res[j]:0)+res[j+1]; // 基本保证:上一次对比时都次数肯定都在这一次的比较之后,所指至少是上一次的次数。bonus,在这某一个位置t s的字母相等了,那么就可以用t的前 (j-1)的子串 加上现在这个位置 j的字母合并成的subsequence 进行匹配,那么次数就是 (j-1)代表的字符串的次数,那就是 res[j]
}
}
return res[t.length()];
}
}
interleaving string
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
int len1=s1.length();
int len2=s2.length();
if(len1+len2!=s3.length()) return false;
String shortStr=len1<len2?s1:s2;
String longStr=len1<len2?s2:s1;
int shortLen = shortStr.length();
int longLen = longStr.length();
boolean[] record = new boolean[1+shortLen];
record[0]=true;
for(int i=0; i<shortLen; i++){ // i is the index in the shortStr, the result is in record[i+1] though
record[i+1] = record[i]&&(shortStr.charAt(i)==s3.charAt(i));
}
for(int j=0; j<longLen; j++){ // j is also the index in the longStr.
record[0] = record[0] && (longStr.charAt(j)==s3.charAt(j));
for(int i=0; i<shortLen; i++){
record[i+1] = (record[i+1]&&(longStr.charAt(j)==s3.charAt(i+j+1))) || (record[i] && (shortStr.charAt(i)==s3.charAt(i+j+1)));
} // when i and j are index in shortStr and longStr, it is i+j+1 in the s3, since it is the length directly matches, not index
}
return record[shortLen];
}
}
edit distance
class Solution {
public int minDistance(String word1, String word2) {
int len1 = word1.length();
int len2 = word2.length();
if(len1==0) return len2;
if(len2==0) return len1;
String shortWord = len1<len2?word1:word2;
String longWord = len1<len2?word2:word1;
int[] record = new int[shortWord.length()+1];
for(int i=0; i<shortWord.length()+1; i++) record[i]=i;
for(int j=0; j<longWord.length(); j++){
int[] newRecord = new int[shortWord.length()+1];
newRecord[0] = j+1; // the first elem present that the (j+1)th char in the longWord
for(int i=0; i<shortWord.length(); i++){
// newRecord[i] keep the distance between shortWord[i-1] and longWord[j], this is the difference!!
// following the above comment, to get record[i+1], we need to compare shortWord[i] and longWord[j];
if(shortWord.charAt(i)==longWord.charAt(j)) newRecord[i+1]=record[i];
else{
newRecord[i+1]=Math.min(newRecord[i], Math.min(record[i], record[i+1]))+1;
}
}
record=newRecord;
}
return record[shortWord.length()];
}
}
// 这题和一般的DP,2D-DP的关键区别是在for loop里面同时有2个array,这是必要的,因为需要斜对角,左上方向的字母所带有的信息来判断!!在总结的时候一定要记录!!