力扣题解(不同的子序列)

115. 不同的子序列

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。

思路:

本题研究的是t在s中出现的次数,注意t一定是小的那个,是s的子串。

dp[i][j]表示t的(0-i)位置的子串由s的(0-j)位置子串所表示的所有 可能。

则此时dp[i][j]需要分成两种情况,一种是包含s[j]的数值,一种是不包含s[j]的数值(之所以这么做,和题目要求是有关的,因为本题要的是所有出现次数,则包含s[j]出现次数一定和不包含s[j]出现次数不重叠,且二者可以表示所有可能,因此这么设计)则此时若包含s[j],则必须由t[i]=s[j],不然s[j]是一定不包含的(因为此时t[i]是一定要被表示的,且是最末尾的一个字符,而s[j]也是最末尾一个字符,二者必须相同).若不包含s[j],则是由s的(0-j-1)来表示t的(0-i).

故dp[i][j]=dp[i][j-1]+dp[i-1][j-1](若数值相同才加这一部分)。

初始时,当i=0,则表示s要表示空串,则一定有且只有一种表示方式(因为s不管是不是空,也只能提出来一个空串)。

在处理这种类似可以组成的所有可能时,一般都利用动态规划,因为再额外加一个字符的所有可能一定是与不加这个字符的可能有关。再者,对于求所有数目,一般初始化需要注意,因为一般不能是默认值零,因为后面加一个字符时的数目一般是用“+=”,而不是常见的xx+k(k是个常数),所以若开始初始化是0,则很有可能所有可能全是0,根本无法出现累加的情况(累加是对各种可能的加合,而全是0则没办法往上走)。

对于同时考虑两个字符串的题,一般是用多维,一维表示一个字符串。不能用一维表示,因为一维无法同时保存太多的信息,只能对一个字符串的某些信息存储,而会忽略对另一个字符串的信息的保存。

再者,需要考虑dp[i][j]的意义,此处dp[i][j]常见的就是表示(0-i),(0-j)的什么,或者表示i到j的什么,具体跟题目要求有关,但一般dp[i][j]求解都是需要和i,j位置元素挂钩的,有时也可能只和其中一个元素挂钩,但无论怎么样,一般都是会将情况分成两种分别探讨,化成两种的好处是清新且方便,若是化成多种情况很容易出现混乱,重叠。

class Solution {
public:
    int numDistinct(string s, string t) {
    
      int n1=t.size();
      int n2=s.size();
      vector<vector<long long>>dp(n1+1,vector<long long>(n2+1,0));
   for(int j=0;j<=n2;j++)
   dp[0][j]=1;
    
      for(int i=1;i<=n1;i++)
      {
        for(int j=1;j<=n2;j++)
        {
          dp[i][j]+=dp[i][j-1];
          int k=0;
          if(t[i-1]==s[j-1])
          k=dp[i-1][j-1];
          dp[i][j]+=k;
        }

      }
     return dp[n1][n2];
    
    
    
    
        }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值