每日一题:动态规划解不同的子序列

问题描述:

给定一个字符串s 和一个字符串 t,计算在s的子序列中 t 出现的个数。

字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置 所组成的新字符串。(例如,"ACE"是"ABCDE"的一个子序列,而"AEC"不是)。

题目数据保证答案符合32位带符号整数范围。

0<=s . length, t. length<=1000, s和t由英文字母组成。

 

动态规划解决:

题目中说“计算在s的子序列中 t 出现的个数。”,翻译就是“在所有s 的子序列中 字符串 t 出现的次数”。

首先,我们定义状态变量,设dp[i][j]表示 字符串t 的前 i 个字符在 s 的前 j 个字符的子序列中出现的次数(也可以说是字符 串s 的前j个字符组成的子序列中,和字符串t 的前i个字符组成的字符串一样的有多少 个)。

那么最终我们只需要求出dp[tlen][ slen]即可(其中tlen和slen分 别表示字符串t和s的长度)。

然后列出递推方程:

1,如果t 的第 i 个字符等于 s 的第 j 个字符,即t.at(i)==s.at(j) 

便有两种情况:

a,若使字符串 s 的第j 个字符 与 字符串 t 的 第i 个字符 匹配,那我们就只需要在 s 的 前 j-1个字符的子序列中找 t 的前 i -1个字符出现的次数 。

b,若使两者不匹配,那么我们就需要在 s 的前 j-1 个字符的子序列中找 t 的前i 个字符 出现的次数。如下图:

 2,如果 t.at(i) ! = s.at(j) ,则只需要在 s 的前 j-1 个字符中 找 t 前i 个字符出现的次数,即 dp[i][j]=dp[i][j-1].

代码:

for (int j = 1; j <= sLength; j++)
{
    if (t.charAt(i - 1) == s.charAt(j - 1)) {
    //如果字符串t的第i个字符和s的第j个字符一样,
    //那么有两种选择,并且两种选择同时发生,所以要相加。
    dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
}
else 
{
    //如果字符串t的第i个字符和s的第j个字符不一样,
    //我们只能用字符串s的前j-1个字符来计算他包含的数量
    dp[i][j] = dp[i][j - 1];
}

最后,找出边界条件。因为空字符串“ ” 是任何字符串的子序列 ,所以 边界条件是:

           dp[0][j] =0

最终代码:

class Solution {
public:
    int numDistinct(string s, string t) 
    {
        int slen=s.size();
        int tlen=t.size();
        if(slen<tlen)
        {
            return 0;
        }
        vector<vector<unsigned long>> dp(tlen+1,vector<unsigned long>(slen+1,0)); 
        for(int j=0;j<=slen;j++)
        {
            dp[0][j]=1;
        }
        for(int i=1;i<=tlen;i++)
        {
            for(int j=1;j<=slen;j++)
            {
                if(t.at(i-1)==s.at(j-1))
                {
                    dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
                }
                else
                {
                    dp[i][j]=dp[i][j-1];
                }
            }
        }
        return dp[tlen][slen];


    }
};

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别抢我的辣条~

老板大气!祝老板身体健康!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值