题目链接: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.

这道题的要求是统计有多少不同的子序列,即字符串S中能找出多少个不同的子序列T。

终于不是树的题目了,接连做了好多天的二叉树了啊。。。

显然,动态规划的思路,采用数组dp[i, j]存储S中的前i个字符能找出不同的子序列(T中前j个字符)的数量。因此,当j等于0的时候,dp[1, 0]等于1。

接下来,

  • 当S[i]与T[j]不同的时候,说明S[i]的出现并不产生影响,因此dp[i+1, j+1] = dp[i, j+1];
  • 当S[i]与T[j]相同的时候,说明S[i]的出现可以产生影响额外的情况,即包含字符S[i]的情况,因此dp[i+1, j+1] = dp[i, j] + dp[i, j+1]。

时间复杂度:O(n)

空间复杂度:O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution
{
public:
    int numDistinct(string S, string T)
    {
        int ls = S.length(), lt = T.length();
        vector<vector<int> > dp(ls + 1, vector<int>(lt + 1, 0));
        
        for(int i = 0; i <= ls ; ++ i)
            dp[i][0] = 1;
        
        for(int i = 1; i <= ls; ++ i)
            for(int j = 1; j <= lt; ++ j)
                if(S[i - 1] == T[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                else
                    dp[i][j] = dp[i - 1][j];
        
        return dp[ls][lt];
    }
};

可以注意到,递推公式只用到了前面1行的情况,因此可以采用一维数组记录情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution
{
public:
    int numDistinct(string S, string T)
    {
        int ls = S.length(), lt = T.length();
        vector<int> dp(lt + 1, 0);
        dp[0] = 1;
        
        for(int i = 1; i <= ls; ++ i)
            for(int j = lt; j > 0; -- j)
                if(S[i - 1] == T[j - 1])
                    dp[j] += dp[j - 1];
        
        return dp[lt];
    }
};