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

  • 法一:二维动态规划

class Solution {
public:
    int numDistinct(string s, string t){
        int n=s.size(),m=t.size();
        if(n<m) return 0;//n是原串的字符数,m是子串的字符数,想在s中找到t,s的字符数一定要大于t的字符数
        //注意用例字符过多,此处只能使用unsigned long long
        //由于字符可以选择0个到n个,故dp数组长需要为n+1
        vector<vector<unsigned long long >> dp(n+1,vector<unsigned long long >(m+1,0));
        //边界,有两个。
        //第一行,原串s为空串,t有字符,此时s无法找到t,全部置0
        //第一列,原串有字符,t为空,此时s字符全部删除可以找到一种情况,全部置1
        for(int i=0;i<=n;i++)
            dp[i][0]=1;
        //填dp数组
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                dp[i][j]+=dp[i-1][j];//情况一,不使用s[i-1]
                if(s[i-1]==t[j-1]) dp[i][j]+=dp[i-1][j-1];//情况二,使用s[i-1]且匹配成功
            }
        }
        return dp[n][m];//返回结果
    }
};
  • 时间复杂度O(n^2)

  • 空间复杂度O(n^2)

  • 思路

    • s是原串,t是子串,求从s找到t的方法数
    • dp[i][j]:s中1~i个字符中找到t中1 ~ j个字符的方法数
    • 状态转移方程:dp[i][j]=dp[i-1][j]+(s[i-1]==t[j-1]?dp[i-1][j-1]:0)
      • 分两种情况,s的第i个字符用或者不用。如果不用,则方法数与dp[i-1][j]相同;如果用,且s的第i个字符与t的第j个字符相同,则方法数与dp[i-1][j-1]相同。将两种情况得到的方法数加起来,就是所求的方法数
  • 方法二:优化空间,一维动态规划

class Solution {
public:
    int numDistinct(string s, string t){
        int n=s.size(),m=t.size();
        if(n<m) return 0;
        //样例字符过多,只能选择unsigned long long
        vector<unsigned long long> dp(m+1,0);
        //pre记录当前未修改前的dp[j]对应二维dp中的dp[i-1][j],cur记录未修改前的dp[j-1]对应二维dp中的dp[i-1][j-1]
        int pre=0,cur=1;
        //填dp数组
        for(int i=1;i<=n;i++)
        {
            dp[0]=1;//类比到二维dp数组,初始化第一列为1,表示s非空t为空串的情况
            cur=1;//对于dp[1]而言,未修改前的dp[0]就是1
            //填当前行
            for(int j=1;j<=m;j++)
            {
                pre=dp[j];//记录未修改的dp[j],为计算dp[j+1]做辅助
                //此处省略了情况一,即不选择s[i-1],此时的dp[j]=dp[j]
                if(s[i-1]==t[j-1]) dp[j]+=cur;//情况二,选择s[i-1]
                cur=pre;//记录未修改前的dp[j],
            }
            
        }
        return dp[m];
    }
};
  • 时间复杂度O(n^2)
  • 空间复杂度O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值