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.

 

思路: 如果简单的想可以用DFS,从S中顺序找到sizeof(T)个字符,等于T即可,输出可能性,复杂度为O(2^n)

所以考虑用动态规划求解,我们可以假设flag[i][j]表示S的前i个字符和T的前j个字符中满足条件的个数;

即S中前i个字符中顺序挑选j个字符来构成T中前j个字符

flag[0][0] = 1;

flag[i][0] i>0 = 1

flag[0][i] i>0 = 0

flag[i][j] 与 flag[i-1][j] flag[i][j-1] 还有flag[i-1][j-1]满足什么关系呢?

假设T遍历到了第j个字符,而S遍历到了第i个字符,前面已经得到了flag[i-1][j] flag[i-1][j-1] flag[i-1][j-1],我们需要思考S中增加第i个字符对结果会造成哪些影响?

思考第i个字符S(i-1) 和 第j个字符T(j-1)关系? 如果不相等,则第i个字符无关紧要,不会对结果造成影响,对subsequence没有影响;

则flag[i][j] = flag[i-1][j]

如果相等呢?这就会对结果有影响,该字符可以作为subsequence的最后一个字符

如果是,则已经挑选出一个,则剩余的i-1个字符为flag[i-1][j-1]

如果不是,则该字符无效,则剩余的i-1个字符中挑选j个字符,为flag[i-1][j] 

则总共 flag[i-1][[j-1] + flag[i-1][j] 

java代码:

  1. public int numDistinct(String S, String T) {
  2. int s1 = S.length();
  3. int t1 = T.length();
  4. if(s1<t1) return 0;
  5. int[][] flag = new int[s1+1][t1+1];
  6. flag[0][0] = 1;
  7. for(int i=1;i<=t1;i++)
  8. flag[0][i] = 0;
  9. for(int i=1;i<=s1;i++) {
  10. flag[i][0] = 1;
  11. }
  12. for(int i=1;i<=s1;i++) {
  13. for(int j=1;j<=i && j<=t1;j++) {
  14. flag[i][j] = flag[i-1][j];
  15. if(S.charAt(i-1)==T.charAt(j-1)) {
  16. flag[i][j] += flag[i-1][j-1];
  17. }
  18. }
  19. }
  20. return flag[s1][t1];
  21. }

参考:http://blog.csdn.net/abcbc/article/details/8978146

遇到这种两个串的问题,很容易想到DP。但是这道题的递推关系不明显。可以先尝试做一个二维的表int[][] dp,用来记录匹配子序列的个数(以S ="rabbbit",T = "rabbit"为例):

 

    r a b b b i t

  1 1 1 1 1 1 1 1

0 1 1 1 1 1 1 1

a 0 1 1 1 1 1 1

b 0 0 2 3 3 3

b 0 0 0 0 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()

posted @ 2014-07-31 22:25  purejade  阅读(78)  评论(0编辑  收藏  举报