动态规划 115. 不同的子序列

本文探讨了如何计算一个字符串S中另一个字符串T的不同子序列出现次数,通过动态规划方法解决这一复杂问题,并提供了详细的算法实现,包括二维动态规划及空间优化后的滚动数组方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

115. 不同的子序列

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

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

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

示例 1:

输入:S = "rabbbit", T = "rabbit"
输出:3
解释:

如下图所示,3 种可以从 S 中得到 "rabbit" 的方案。
(上箭头符号 ^ 表示选取的字母)

rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例 2:

输入:S = "babgbag", T = "bag"
输出:5
解释:

如下图所示,5 种可以从 S 中得到 "bag" 的方案。 
(上箭头符号 ^ 表示选取的字母)

babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^

解题
动态规划——S的前i个字符表示T的前j个字符的子序列有多少种;
遍历S和T,若S【i】==T【j】,dp[i][j]= dp[i-1][j-1]+dp[i-1][j]; (使用i作为t子序列第j个字符+不使用i作为第j个字符)
若S【i】!=T【j】,dp[i][j]=dp[i-1][j],只能不适用S[i]作为子序列T的第j个字符。

初始化
dp【i】【0】为1; S中每个子串对空字符串都有一种表示方法;

二维动态规划

class Solution {
public:
    int numDistinct(string s, string t) {
        //s的前i个数可以的子序列 中等于t的前j个数的个数
        int snum=s.size();
        int tnum=t.size();
        dp.resize(snum+1,vector<long long>(tnum+1,0));

        for(int i=0;i<snum;i++)
            dp[i][0]=1;
         for(int j=1;j<=tnum;j++)
           for(int i=1;i<=snum;i++){
               if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j]+dp[i-1][j-1]; 
               //不将第i个字符放入子序列的个数+将第i哥字符放入子序列最后一个的个数
               else dp[i][j]=dp[i-1][j];
               //不相等则不用加
            }
        

        return (int)dp[snum][tnum];
    }

private:
    vector<vector<long long>> dp;
};

空间优化:滚动数组
改为滚动数组,j需要从后向前
因为dp[j]的滚动用到【i-1】【j-1】,即上一层的j-1,故需保留j-1,从后往前滚动!

class Solution {
public:
    int numDistinct(string s, string t) {
        //s的前i个数可以的子序列 中等于t的前j个数的个数
        int snum=s.size();
        int tnum=t.size();
        dp.resize(tnum+1,0);

        for(int i=0;i<snum;i++)
            dp[0]=1;

        for(int i=1;i<=snum;i++)
         for(int j=tnum;j>0;j--)
           {
               if(s[i-1]==t[j-1]) dp[j]=dp[j]+dp[j-1]; 
               //不将第i个字符放入子序列的个数+将第i哥字符放入子序列最后一个的个数
               //else dp[j]=dp[j];
               //不相等则不用加
            }
        return (int)dp[tnum];
    }

private:
    vector<long long> dp;
};

总结
递推公式——由字符的比较得到dp的递推公式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值