代码随想录算法训练营第五十四天 | LeetCode 392. 判断子序列、115. 不同的子序列

简介: 代码随想录算法训练营第五十四天 | LeetCode 392. 判断子序列、115. 不同的子序列

代码随想录算法训练营第五十四天 | LeetCode 392. 判断子序列、115. 不同的子序列

文章链接:判断子序列不同的子序列

视频链接:判断子序列不同的子序列

1. LeetCode 392. 判断子序列

1.1 思路

  1. 本题是给两个字符串让我们判断字符串 s 是不是字符串 t 的子序列。子序列要求不能改变数组顺序,不要求连续,其实这题和1143. 最长公共子序列是一样的,本题中如果两个字符串的最长公共子序列长度是字符串 s 的长度的话,那么字符串 s 就应该是字符串 t 的子序列了。本题也算是编辑距离的入门题
  2. dp 数组及其下标的含义:用一个二维数组就可以表示出两个字符串里每一个元素它的是否相同的情况,dp[i][j]:以 i-1 为结尾的字符串 s 和以 j-1 为结尾的字符串 t 的相同子序列的长度为 dp[i][j],如果这个长度就是字符串 s 的长度,那字符串 s 就是字符串 t 的子序列。这里定义 i-1 和 j-1 是为了避免对第一行和列进行复杂的初始化,定义为 i 和 j 也行,就是麻烦些
  3. 递推公式:有两个情况,判断的就是两个元素是否相同。if(s[i-1]==t[j-1])为什么判断的是 i-1 和 j-1,因为我们 dp 数组就是这么定义的。如果相等 dp[i][j]=dp[i-1][j-1]+1,含义就是这两个元素相等了,就在前面的基础上加 1。如果不相等 else 只能在 t 中删除元素,即如果 s 的 i-1 位置和 t 的 j-1 位置不相等了,就把 t 的 j-1 位置删除掉了,考虑的就是 t 的 j-2 前面的字符串和 s 的 i-1 前面的字符串的相同子序列长度了,也就是 dp[i][j-1],dp[i][j]=dp[i][j-1],其实可以理解为继承的意思

  4. dp 数组的初始化:根据递推公式可以看出推导方向,根据这个推导方向,就需要初始化第一行 dp[0][j] 和第一列 dp[i][0],根据 dp 数组的含义,这里是 0 的话是需要以 -1 为结尾的相同子序列也就是空串的相同子序列长度,也就是 0 了,因此 dp[i][0]=dp[0][j]=0,其余下标根据递推公式会被覆盖的,因此可以不管,默认为 0 即可
  5. 遍历顺序:根据推导方向,一定要从左到右从上到下,避免赋的是空值 for(int i=1;i<=s.length();i++)for(int j=1;j<=t.length();j++)为什么从 1 开始,因为 0 已经初始化了。为什么要取等于号,因为 dp 数组是从 i-1 和 j-1 开始,不取等于号会漏了最后一个状态,而我们最初定义 dp 数组会是 [s.length()+1][t.length()+1]。最终结果是在 dp[s.length()][t.length()],如果和 s.length()相等就是 true,反之 false
  6. 打印 dp 数组:用于 debug

1.2 代码

class Solution {
    public boolean isSubsequence(String s, String t) {
        int length1 = s.length(); int length2 = t.length();
        int[][] dp = new int[length1+1][length2+1];
        for(int i = 1; i <= length1; i++){
            for(int j = 1; j <= length2; j++){
                if(s.charAt(i-1) == t.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1] + 1;
                }else{
                    dp[i][j] = dp[i][j-1];
                }
            }
        }
        if(dp[length1][length2] == length1){
            return true;
        }else{
            return false;
        }
    }
}

2. LeetCode 115. 不同的子序列

2.1 思路

  1. 本题求的是子序列,不要求连续,问的是 s 有多少个 t 这样的子序列,其实就是相当于问 s 可以有多少种删除元素的方式。
  2. dp 数组及其下标的含义:对于两个字符串比较里面的元素是否相同的情况是定义二维数组,dp[i][j]:以 i-1 为结尾的 s 中有以 j-1 为结尾的 t 的个数为 dp[i][j]。为什么定义 i-1 和 j-1 上面解释过了
  3. 递推公式:if(s[i-1]==t[j-1])为什么判断的是 i-1 和 j-1,看看 dp 数组的含义,如果相等就不需要考虑这两个字母,而是 i-2 和 j-2 为结尾的个数即 dp[i-1][j-1],那也可以考虑不使用 s[i-1],为什么呢?举例:s=bagg,t=bag,如果不使用 s[3] 此时前面的也可以等于 t,这种情况不使用它就相当于把 s[i-1] 删除掉了,此时的情况就是 dp[i-1][j]。而我们这里不求 t 有多少个 s,因此不能不考虑 t[j-1]。那因此 dp[i][j] 就应该是考虑 s[i-1] 和不考虑 s[i-1] 的情况相加,dp[i][j]=dp[i-1][j-1]+dp[i-1][j]。如果 s[i-1]!=t[j-1] 就是把 s[i-1] 删除的情况,就是不考虑它了,就 dp[i][j]=dp[i-1][j]。

  4. dp 数组的初始化:根据递推公式可以看出推导方向,因此最上方的第一行和第一列一定要初始化,dp[0][j] 第一行这种情况就是以-1 为结尾的空字符串 s 有以 j-1 为结尾的 t 的个数,空字符串肯定没有 t,因此初始化为 0;dp[i][0] 第一列这种情况就是以 i-1 为结尾的 s 有以-1 为结尾的空字符串 t 的个数,那就应该是 1 了,s 肯定有一个空字符串,因此初始化为 1,而 dp[0][0] 也就是这种情况了,也初始化为 1
  5. 遍历顺序:根据推导方向从左到右从上到下,因此 for(int i=1;i<=s.length();i++)for(int j=1;j<=t.length();j++),为什么取 1 以及为什么要等于号上面解释过了。最终结果是在 dp[s.length()][t.length()]
  6. 打印 dp 数组:用于 debug

2.2 代码

class Solution {
    public int numDistinct(String s, String t) {
        int[][] dp = new int[s.length() + 1][t.length() + 1];
        for (int i = 0; i < s.length() + 1; i++) {
            dp[i][0] = 1;
        }
        for (int i = 1; i < s.length() + 1; i++) {
            for (int j = 1; j < t.length() + 1; j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                }else{
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[s.length()][t.length()];
    }
}
相关文章
|
2天前
|
算法 关系型数据库 C语言
卡尔曼滤波简介+ 算法实现代码(转)
卡尔曼滤波简介+ 算法实现代码(转)
13 4
|
2天前
|
机器学习/深度学习
leetcode代码记录(旋转图像
leetcode代码记录(旋转图像
8 0
|
2天前
|
算法
leetcode代码记录(全排列 II
leetcode代码记录(全排列 II
9 4
|
2天前
|
算法
leetcode代码记录(全排列
leetcode代码记录(全排列
9 1
|
2天前
|
索引
leetcode代码记录(Z 字形变换
leetcode代码记录(Z 字形变换
7 1
|
2天前
leetcode代码记录(最长回文子串
leetcode代码记录(最长回文子串
7 2
|
2天前
leetcode代码记录(回文数
leetcode代码记录(回文数
8 1
|
1天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
2天前
|
存储 算法 数据可视化
基于harris角点和RANSAC算法的图像拼接matlab仿真
本文介绍了使用MATLAB2022a进行图像拼接的流程,涉及Harris角点检测和RANSAC算法。Harris角点检测寻找图像中局部曲率变化显著的点,RANSAC则用于排除噪声和异常点,找到最佳匹配。核心程序包括自定义的Harris角点计算函数,RANSAC参数设置,以及匹配点的可视化和仿射变换矩阵计算,最终生成全景图像。
|
2天前
|
算法 Serverless
m基于遗传优化的LDPC码NMS译码算法最优归一化参数计算和误码率matlab仿真
MATLAB 2022a仿真实现了遗传优化的归一化最小和(NMS)译码算法,应用于低密度奇偶校验(LDPC)码。结果显示了遗传优化的迭代过程和误码率对比。遗传算法通过选择、交叉和变异操作寻找最佳归一化因子,以提升NMS译码性能。核心程序包括迭代优化、目标函数计算及性能绘图。最终,展示了SNR与误码率的关系,并保存了关键数据。
12 1

热门文章

最新文章