Leetcode: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.

题意:字符串T为从字符串S中删除n个字符(n >= 0)所得,字符之间的相对顺序保持不变,求T的个数。

有两种方法可解此类问题:1)递归;2)动态规划。

1)递归

递归体:循环扫描两个字符串。当两个当前字符相同时,对余下的两个子串递归;当前两个字符不同时,在S串的子串中寻找T的Distinct Subsequences;

递归结束条件:当S为空串时返回0;T为空串时返回1。

代码如下:

   int numDistinct(string S, string T) {
        
        if(S.length() == 0)return 0;
        if(T.length() == 0)return 1;
        int num = 0;
        for(int i = 0;i < S.length();i++)
        {
            if(S[i] == T[0])
            {
               num += numDistinct(S.substr(i + 1),T.substr(1));
            }
        }
        return num;
 }
};
递归算法会超时!
2)动态规划

遇到这种比较两个字符串的问题,要自然而然的想到动态规划,类似的经典的题目如:最长公共子序列;最长公共子串等问题。在这些问题中都利用了一个二维数组来表示当前的状态。设置状态变量dp[i][j]表示在S[ 0,...,i ]中T[ 0,..,j ]的Distinct Subsequences的个数。显然,dp[S.length()-1][T.length() - 1]即为所求。状态转移方程如下:

1)dp[0][0] = 1,即两个都为空串时也是有效滴,个数为1;

2)dp[0][1,..,len_T] = 0,即当S为空时,找不到这样的子串,个数为0;

3)dp[1,...,len_S][0] = 1,即当T为空时,在S的1到len_S的任意位置处,这样的子串个数均为1;

4)当S[i - 1] == T[j - 1]时,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

5)当S[i - 1] != T[j - 1]时,dp[i][j] = dp[i - 1][j - 1];

代码如下:

class Solution {
public:
    int numDistinct(string S, string T) {
        
        if(S.length() == 0)return 0;
        if(T.length() == 0)return 1;

        int len_S = S.length();
        int len_T = T.length();
        
        int **dp = new int *[len_S + 1];
        for(int i = 0;i < len_S + 1;i++)
        {
            dp[i] = new int [len_T + 1];
        }
        dp[0][0] = 1;
        for(int i = 1;i < len_S + 1;i++)
        {
            dp[i][0] = 1;
        }
        
        for(int i = 1;i < len_T + 1;i++)
        {
            dp[0][i] = 0;
        }
        
        for(int i = 1;i <= len_S;i++)
            for(int j = 1;j <= len_T;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];
            }
        int num = dp[len_S][len_T];
        for(int i = 0;i < len_S + 1;i++)
            delete []dp[i];
        delete []dp;
        return num;
    }
};

总结+牢骚:要深刻理解递归算法和动态规划算法啊!刚开始我根本就没有思路,看到网上别人的思路之后才知道原来可以用递归和动态规划解决,本人简直是弱爆了!以后找工作咋办啊?!智商捉急啊!根本就没发现这个题目中还蕴含着递归的规律!以后遇到类似的比较两个字符串的题目时也要学会利用二维数组这个工具,试试用动态规划解决。当然,根本的还是要发现题目中蕴含的规律啊!如果只是直接套用那就是碰运气,如果题目改变一下还是不会。嗨~~~,还是没有抓住递归和动态规划的实质!不说了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值