代码随想录 115.不同的子序列

思路:本题也是编辑距离类型问题。本题相当于只有删除操作,不考虑替换增加之类的。

动规五部曲:

1.确定dp数组(dp table)及其下标的含义:dpij表示以i - 1为结尾的s子序列中,出现以j - 1为结尾的t的个数为dpij。

2.确定递推公式:分为两种情况。

(1)si - 1与tj - 1相等:dpij可以由两部分组成。

------一部分是用si - 1来匹配,个数为dpi - 1j - 1。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要dpi - 1j - 1。

------另一部分是不用si - 1来匹配,个数为dpi - 1j。

所以此时递推公式为dpij = dpi - 1j - 1 + dpi - 1j。

(2)si - 1与tj - 1不相等:dpij只有一部分组成,那就是不用si - 1来匹配(模拟在s中删除这个元素),即:dpi - 1j。此时递推公式为:dpij = dpi - 1j。

为什么只考虑不用si - 1来匹配的情况,而没有考虑不用tj - 1来匹配的情况?

因为是要求s中有多少个t,而不是求t中有多少个s,所以只考虑s中删除元素的情况。

3.dp数组如何初始化:

(1)从递推公式dpij = dpi - 1j - 1 + dpi - 1j和dpij = dpi - 1j可以看出,dpij是从上方和左上方推导而来,如下图所示。那么dpi0和dp0j一定是要初始化的。

(2)初始化之前,先回顾dpij的定义。

------dpi0表示:以i - 1为结尾的s可以随便删除元素,出现空字符串的个数。因此dpi0 = 1。

------dp0j表示:空字符串s可以随便删除元素,出现以j - 1为结尾的字符串t的个数。因此dp0j = 0,因为s无法变为t。

------dp00:dp00应该为1,因为空字符串s可以删除0个元素变成空字符串t。

4.确定遍历顺序:从递推公式dpij = dpi - 1j - 1 + dpi - 1j和dpij = dpi - 1j可以看出来,dpij是根据左上方和正上方推导出来的。所以遍历顺序为从上到下,从左到右,以保证dpij可以根据之前计算出的数值进行计算。代码如下所示。

cpp 复制代码
for (int i = 1; i <= s.size(); i++) {
    for (int j = 1; j <= t.size(); j++) {
        if (s[i - 1] == t[j - 1]) {
            dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
        } else {
            dp[i][j] = dp[i - 1][j];
        }
    }
}

5.举例推导dp数组:以s:"baegg",t:"bag"为例,dp数组的状态如下所示。

附代码:

java 复制代码
class Solution {
    public int numDistinct(String s, String t) {
        int len1 = s.length();
        int len2 = t.length();
        int[][] dp = new int[len1 + 1][len2 + 1];
        for(int i = 0;i < len1 + 1;i++){
            dp[i][0] = 1;
        }
        for(int i = 1;i < len1 + 1;i++){
            for(int j = 1;j < len2 + 1;j++){
                if(s.charAt(i - 1) == t.charAt(j - 1)){
                    //既可以使用主串s的最后一个字符s[i - 1]去匹配t的最后一个字符t[i - 1]
                    //也可以不使用主串s的最后一个字符s[i - 1]去匹配t的最后一个字符t[j - 1]
                    //这两种选择是互斥的,且覆盖了所有可能
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                }else{
                    //主串s的最后一个字符s[i - 1]不能用来匹配t的最后一个字符t[i - 1]
                    //因此必须用s[0..i - 2]去匹配t[0..j - 1]
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[len1][len2];
    }
}
相关推荐
CCblandy11 分钟前
向量检索 ANN 参数实测:换一种数据分布,recall 掉了 51 个百分点
人工智能·python·算法·自然语言处理·性能优化
CS创新实验室12 分钟前
一棵树怎么做到“自平衡还不太费力“?——红黑树的旋转与染色
数据结构·算法·红黑树·408·计算机考研
Logic10124 分钟前
C语言/数据结构位运算题解:异或XOR找出被挑选一次的果子编号——只出现一次的数字
c语言·数据结构·算法·数组·位运算·时间复杂度·空间复杂度
深圳市快瞳科技有限公司29 分钟前
面向端侧部署的多帧宠物身份识别:完整性评分机制与工程约束
人工智能·算法·计算机视觉·端侧ai·宠物识别·宠物ai·宠物身份识别
悠仁さん2 小时前
非类型模板参数的特化与偏特化
java·数据结构·算法
垆边人似月.2 小时前
最优河堤加固(二分答案 + 前缀和)
算法
171320330计算机毕设编程3 小时前
计算机毕业设计 基于Hadoop的新能源汽车发展前景分析 LW PPT
java·大数据·hadoop·python·算法·随机森林·线性回归
垆边人似月.3 小时前
幻兽防御战(贪心算法)
数据结构·算法
DongQiShanRen3 小时前
六根硬件映射(下):物理闭环五步法,抽一条已实装的看
大数据·jvm·人工智能·算法·rust·哈希算法·集成学习
Code_Solitude3 小时前
c语言:指针(3)+冒泡排序
java·c语言·算法