题目有些不好理解,实际上的意思就是在S中找T包含的所有字符(要按T的顺序),一共有几种组合?
动态规划。不会做,参考了
http://leetcodesolution.blogspot.com/2013/09/distinct-subsequences.html
http://blog.csdn.net/abcbc/article/details/8978146
特别是第一篇:
- the rest of string T is a subsequence the rest of string S, or
- T is a subsequence of the rest of string S
- f[i][j] = f[i+1][j+1] + f[i+1][j], if S[i] == T[j]
- f[i][j] = f[i+1][j], if S[i] != T[j]
- f[i][j] =1, if j == T.size()
- f[i][j] = 0, if I ==S.size() && j != T.size()
package Level4;
/**
*
* Distinct Subsequences
*
Given a string S and a string T, count the number of distinct subsequences of T in S.
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).
Here is an example:
S = "rabbbit", T = "rabbit"
Return 3.
*
*/
public class S115 {
public static void main(String[] args) {
}
public int numDistinct(String S, String T) {
int m = S.length();
int n = T.length();
if(m==0 || n==0){
return 0;
}
int[][] dp = new int[m+1][n+1];
for(int i=m; i>=0; i--){
for(int j=n; j>=0; j--){
if(j == n){ // 如果j已经到达T的末端,就说明T中所有的字符都在S中找到
dp[i][j] = 1;
}else if(i == m){ // 如果i到达S的末端,且j还没到达T的末端,则说明无法找到满足的subsequence
dp[i][j] = 0;
}else if(S.charAt(i) != T.charAt(j)){ // 如果当前比较的字符pair不同,则说明T肯定不会在以i开头的序列中,要有也只能在以i+1开头的子序列
dp[i][j] = dp[i+1][j];
}else{ // 如果当前比较的字符pair相同,则说明T可能在以i开头的序列中,也可能在以i+1开头的序列中
dp[i][j] = dp[i+1][j+1] + dp[i+1][j];
}
}
}
return dp[0][0];
}
}
最好的解释:
遇到这种两个串的问题,很容易想到DP。但是这道题的递推关系不明显。可以先尝试做一个二维的表int[][] dp,用来记录匹配子序列的个数(以S ="rabbbit"
,T = "rabbit"
为例):
r a b b b i t
1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3
从这个表可以看出,无论T的字符与S的字符是否匹配,dp[i][j] = dp[i][j - 1].就是说,假设S已经匹配了j - 1个字符,得到匹配个数为dp[i][j - 1].现在无论S[j]是不是和T[i]匹配,匹配的个数至少是dp[i][j - 1]。除此之外,当S[j]和T[i]相等时,我们可以让S[j]和T[i]匹配,然后让S[j - 1]和T[i - 1]去匹配。所以递推关系为:
dp[0][0] = 1; // T和S都是空串.
dp[0][1 ... S.length() - 1] = 1; // T是空串,S只有一种子序列匹配。
dp[1 ... T.length() - 1][0] = 0; // S是空串,T不是空串,S没有子序列匹配。
dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length()
public class Solution {
public int numDistinct(String S, String T) {
int[][] cnt = new int[T.length()+1][S.length()+1];
for(int j=0; j<S.length(); j++) {
cnt[0][j] = 1;
}
for(int i=1; i<T.length(); i++) {
cnt[i][0] = 0;
}
for(int i=1; i<=T.length(); i++) {
for(int j=1; j<=S.length(); j++) {
if(T.charAt(i-1) != S.charAt(j-1)) {
cnt[i][j] = cnt[i][j-1]; // The old way to match
} else { // Match, it allows us to have a new way to match
cnt[i][j] = cnt[i][j-1] + cnt[i-1][j-1]; // old way + new way
}
}
}
return cnt[T.length()][S.length()];
}
}
附带递归解法:
public int numDistinct(String S, String T) {
// Start typing your Java solution below
// DO NOT write main() function
if (S.length() == 0) {
return T.length() == 0 ? 1 : 0;
}
if (T.length() == 0) {
return 1;
}
int cnt = 0;
for (int i = 0; i < S.length(); i++) {
if (S.charAt(i) == T.charAt(0)) {
cnt += numDistinct(S.substring(i + 1), T.substring(1));
}
}
return cnt;
}
这道题可以作为两个字符串DP的典型:
两个字符串:
先创建二维数组存放答案,如解法数量。注意二维数组的长度要比原来字符串长度+1,因为要考虑第一个位置是空字符串。
然后考虑dp[i][j]和dp[i-1][j],dp[i][j-1],dp[i-1][j-1]的关系,如何通过判断S.charAt(i)和T.charAt(j)的是否相等来看看如果移除了最后两个字符,能不能把问题转化到子问题。
最后问题的答案就是dp[S.length()][T.length()]
还有就是要注意通过填表来找规律。
http://blog.csdn.net/abcbc/article/details/8978146