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;
}
原文地址:https://www.cnblogs.com/wuchanming/p/4117925.html