首页 > 代码库 > Distinct Subsequences

Distinct Subsequences

Dynamic Programming

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,总共有几种不同的删除方法

设S的长度为lens,T的长度为lent

算法1:递归解法,首先,从个字符串S的尾部开始扫描,找到第一个和T最后一个字符相同的位置k,那么有下面两种匹配:a. T的最后一个字符和S[k]匹配,b. T的最后一个字符不和S[k]匹配。a相当于子问题:从S[0...lens-2]中删除几个字符得到T[0...lent-2],b相当于子问题:从S[0...lens-2]中删除几个字符得到T[0...lent-1]。那么总的删除方法等于a、b两种情况的删除方法的和。递归解法代码如下,但是通过大数据会超时:

class Solution {public:    int numDistinct(string S, string T) {        // IMPORTANT: Please reset any member data you declared, as        // the same Solution instance will be reused for each test case.        return numDistanceRecur(S, S.length()-1, T, T.length()-1);    }    int numDistanceRecur(string &S, int send, string &T, int tend)    {        if(tend < 0)return 1;        else if(send < 0)return 0;        while(send >= 0 && S[send] != T[tend])send--;        if(send < 0)return 0;        return numDistanceRecur(S,send-1,T,tend-1) + numDistanceRecur(S,send-1,T,tend);    }};

参考:http://www.cnblogs.com/TenosDoIt/p/3440022.html

http://yutianx.info/blog/2014/09/25/leetcode-distinct-subsequences.html

遇到这种两个串的问题,很容易想到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()

实现代码:

#include<iostream>#include<string>using namespace std;class Solution {public:    int numDistinct(string S, string T) {        int slen=S.length();        int tlen=T.length();        if(tlen==0)            return 1;        if(slen==0&&tlen)            return 0;        int dp[slen+1][tlen+1];        dp[0][0]=1;        int i,j;        for(i=1;i<=slen;i++)            dp[i][0]=1;        for(i=1;i<=tlen;i++)            dp[0][i]=0;        for(i=1;i<=slen;i++)        {            for(j=1;j<=tlen;j++)            {                if(S[i-1]==T[j-1])                    dp[i][j]=dp[i-1][j]+dp[i-1][j-1];                else                    dp[i][j]=dp[i-1][j];            }        }        return dp[slen][tlen];    }};int main(){    Solution s;    string S="rabbbit";    string T="rabbit";    cout<<s.numDistinct(S,T)<<endl;}

 

Distinct Subsequences