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

题目描述:

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

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

题目数据保证答案符合 32 位带符号整数范围。
示例:
输入:S = “babgbag”, T = “bag”
输出:5
解释:

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

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

思路:

1.确定状态:这道题输出的结果,依赖于字符串s和t,所以需要准备一个二维数组res[][];
我们通过观察示例可以发现,当拿t字符串中的前一个、前两个和前三个字符与s比较,结果是有规律的。这也是我们自己手动比较时的大概步骤,先找到s字串中和t[0]相同的位置,然后再对其他位进行比较。
所以可以设res[i][j],代表s字串的前j个字符中,包含t字串前i个字符的子串数量;
2.找到状态转移方式:
当i不变,j增加时,如果t[i] == s[j+1],则之前所有符合条件的结果,都可以再生效一次;
比如s字串前j个字串为“babag”,t字串的前i个字串为“bag”,则此时res[i][j] = 3;如果s[j+1] = t[i] = ‘g’,那么s字串前面的j个字符满足的情况会继续满足;之前满足t[i-1]的情况,也会在此生效;
所以res[i][j] = res[i-1][j-1] + res[i][j-1]; 其实把这个二维数组画出来大概就都懂了。
3.边界情况:
s为空时输出0,t为空时输出1,因为空集也是子集。然后从小到大求出res[t.size-1][s.size-1];

class Solution {
public:
    int numDistinct(string s, string t) {
       int m = s.size();
       int n = t.size();
       if( m == 0 )
            return 0;
        if(n == 0)
            return 1;
       vector<vector<long long int>> a(n, vector<long long int>(m, 0));
       if(s[0] == t[0])
            a[0][0] = 1;
       for(int i = 1; i<m; ++i){
           if(s[i] == t[0])
                a[0][i] = a[0][i-1]+1;
            else
                a[0][i] = a[0][i-1];
       } 
       for(int i = 1; i<n; ++i){
           for(int j = i; j<m; ++j){
               if(s[j] == t[i])
                   a[i][j] = a[i-1][j-1] + a[i][j-1];
               else
                    a[i][j] = a[i][j-1];
           }
       }
       return a[n-1][m-1];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值