115. Distinct Subsequences
动态规划它来咧!
题干:
Given a string S and a string T, count the number of distinct subsequences of S which equals T.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
解释:
这个题让我们用S的子序列去构建T,返回可能的种类数。
思考:
还是那句话,看到字符串匹配,不要想dfs,就是dp来做。如果这个题是子串,那么dp ij一定是从左,左上,上,3个方向产生的,问题是现在要的是子序列,我们不妨来看一下以s中第i个字符结尾的子序列 等于T中第j个字符结尾的字串的种类,如果s i==t j,那么dp ij就等于s之前所有小于i的子序列能构成j-1的种类之和,也就是sum dp :j-1 如果s i!=t j,那么dp ij=0. 最后我们只要返回sum dp【:】【j】就行了.OJ通过了,但是时间效率是8%。 但是实际上这种方法还是落入了俗套,因为dp本质上就是研究当前位置和左,上,左上之间的关系。所以dp ij直接设定为所有的种类,如果当前字符能用,那么就等于用上这字符(左上)或者是不用上这个字符,直接用之前的结果即可,也就是以它结尾和不以它结尾。这样递推即可得到。 当然最好的办法还是直接画表,然后找关系就行。
答案:
class Solution {
public int numDistinct(String s, String t) {
//valid input
int m=s.length();
int n=t.length();
if (m==0 || n==0){
return 0;
}
int[][] dp = new int[m+1][n+1];
//init
for (int i =0;i<m;i++){
if (s.charAt(i)==t.charAt(0)){
dp[i][0]= 1;
}
}
for (int i=1;i<m;i++ ){
for (int j=1;j<n;j++){
if (i<j){
dp[i][j]=0;
continue;
}
if (s.charAt(i)==t.charAt(j)){
dp[i][j]=sum(dp,i-1,j-1);
}
else{
dp[i][j]=0;
}
}
}
return sum(dp,m-1,n-1);
}
public int sum(int[][] dp, int end, int j){
int count =0;
for (int i=0;i<=end;i++){
count+=dp[i][j];
}
return count;
}
}
答案补充:
/**
- @author li
- @version 1.0
- @date 2019-04-10 20:58
- 思路:
-
设dp[i][j]表示s[0:i-1]的子序列中t[0:j-1]出现的次数,则 -
1.若s[i-1] == t[j-1] => dp[i][j] = dp[i-1][j-1] (用s[i-1]与t[j-1]配对) + dp[i-1][j](抛弃s[i-1],不用s[i-1]与t[j-1]配对) -
2.若s[i-1] != t[j-1] => dp[i-1][j] (直接抛弃s[i-1],不用s[i-1]与t[j-1]配对)
**/ class Solution { public int numDistinct(String s, String t) { if (s == null || s.length() == 0) { return 0; } int m = s.length(); int n = t.length();
int[][] dp = new int[m + 1][n + 1];
//初始化dp[i][0] = 1
for (int i = 0; i <= m; i++) {
dp[i][0] = 1;
}
//按t[0:0] => t[0:n]的顺序依次匹配
for (int j = 1; j <= n; j++) {
//因为当i<j时 s[0:i-1] 的长度比t[0:j-1]小,所以可以忽略
for (int i = j; i <= m; i++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[m][n];
}
}