LeetCode 打卡day54-55 动态规划之编辑距离问题


知识总结

今天学习动态规划里面的编辑距离问题, 有几道类似的题目, 可以使用相同的模板来做


Leetcode 392. 判断子序列

题目链接

题目说明

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

在这里插入图片描述

代码说明

方法1 , 使用双指针可以比较快的做出了, 相等的话两个指针都往前进, 不相等就只走t的指针

class Solution {
    
    
    public boolean isSubsequence(String s, String t) {
    
    
        int index = 0;
        int len1 = s.length(), len2 = t.length();
        if(len1 == 0) return true;
        if(len2 == 0) return false;
        for(int i = 0; i < t.length(); i++){
    
    
            if(s.charAt(index) == t.charAt(i)){
    
    
                index++;
                if(index == s.length()){
    
    
                    return true;
                }
            }
        }
        return false;
    }
}

方法2, 当然我们还是要学会用动态规划的思想来解决该系列问题
这个问题可以转换成找s, t的最大公共序列的长度, 如果该长度=s.长度, 则t包含了s.

扫描二维码关注公众号,回复: 15690585 查看本文章
class Solution {
    
    
    public boolean isSubsequence(String s, String t) {
    
    
        int len1 = s.length(), len2 = t.length();
        // dp[i][j] 代表着以i-1结尾的s和j-1结尾的t的最大公共子序列长度
        int[][] dp = new int[len1+1][len2+1];
        for(int i = 1; i <= len1; i++){
    
    
            for(int j = 1; j <=len2; 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];
                }
            }
            // System.out.println(Arrays.toString(dp[i]));
        }
        return dp[len1][len2] == len1;
   
    }
}

Leetcode 115. 不同的子序列

题目链接

题目说明

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数。

题目数据保证答案符合 32 位带符号整数范围。

在这里插入图片描述

代码说明

这个题目还挺难的,第一次做的话可能没有思路。
难点在于递推公式如何求出来:

  1. dp数组 // dp[i][j] 表示以i-1 结尾的s字符串中包含多少个以j-1结尾的t字符串
  2. 递推公式

if(s.charAt(i-1) == t.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] + dp[i-1][j]; // 选择使用s[i-1] + 选择不使用s[i-1]的次数加起来
}else{
dp[i][j] = dp[i-1][j]; // 不相等的话只能依靠前面的
}
设置i-1, j-1 是为了初始化的时候更加方便。

class Solution {
    
    
    public int numDistinct(String s, String t) {
    
    
        int len1 = s.length(), len2 = t.length();
        int[][] dp = new int[len1+1][len2+1];
        // dp[i][j] 表示以i-1 结尾的s字符串中包含多少个以j-1结尾的t字符串


        for(int i = 0; i<=len1; i++){
    
    
            dp[i][0] = 1; 
        }

        for(int i = 1; i <= len1; i++){
    
    
            for(int j = 1; j <= len2; j++){
    
    
                if(s.charAt(i-1) == t.charAt(j-1)){
    
    
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j]; // 选择使用s[i-1] + 选择不使用s[i-1]的次数加起来
                }else{
    
    
                    dp[i][j] = dp[i-1][j];
                }
            }
            // System.out.println(Arrays.toString(dp[i]));
        }

        return dp[len1][len2];
    }
}

Leetcode 583. 两个字符串的删除操作

题目链接

题目说明

给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。

每步 可以删除任意一个字符串中的一个字符。
在这里插入图片描述

代码说明

dp数组含义
dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
递推公式
当word1[i - 1] 与 word2[j - 1]相同的时候
当word1[i - 1] 与 word2[j - 1]不相同的时候

情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1
情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1
情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2, 情况三的结果会等于情况1

这题难在初始化时, dp[i][0] = i 而不是1
如果相等, 说明不需要删除, dp[i][j] = dp[i-1][j-1], 如果不相等, 则取小的最小删除数再加1.

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        int len1 = word1.length(), len2 = word2.length();
        int[][] dp = new int[len1+1][len2+1];

        for(int i = 0; i <= len1; i++) dp[i][0] = i;
        for(int j = 0; j <= len2; j++) dp[0][j] = j;
        for(int i = 1; i <= len1; i++){
    
    
            for(int j = 1; j <= len2; j++){
    
    
                if(word1.charAt(i-1) == word2.charAt(j-1)){
    
    
                    dp[i][j] = dp[i-1][j-1];
                }else{
    
    
                    dp[i][j] = Math.min(dp[i][j-1], dp[i-1][j]) + 1;
                }
            }
            // System.out.println(Arrays.toString(dp[i]));
        }
        return dp[len1][len2];
    }
}

Leetcode 72. 编辑距离

题目链接

题目说明

给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符

在这里插入图片描述

代码说明

将上面那题弄懂之后, 难题也变简单了, 就是增加了一个表达式的
dp[i][j] = Math.min(dp[i][j-1], Math.min(dp[i-1][j], dp[i-1][j-1])) + 1;
以前需要删除两下的操作, 我可以通过替换一步就可以做出来。

情况三由:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2
变成了dp[i-1][j-1] + 1 的替换操作

class Solution {
    
    
    public int minDistance(String word1, String word2) {
    
    
        int len1 = word1.length(), len2 = word2.length();
        int[][] dp = new int[len1+1][len2+1];

        for(int i = 0; i <= len1; i++) dp[i][0] = i;
        for(int j = 0; j <= len2; j++) dp[0][j] = j;
        for(int i = 1; i <= len1; i++){
    
    
            for(int j = 1; j <= len2; j++){
    
    
                if(word1.charAt(i-1) == word2.charAt(j-1)){
    
    
                    dp[i][j] = dp[i-1][j-1];
                }else{
    
    
                    dp[i][j] = Math.min(dp[i][j-1], Math.min(dp[i-1][j], dp[i-1][j-1])) + 1; 
                }
            }
            // System.out.println(Arrays.toString(dp[i]));
        }
        return dp[len1][len2];
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45872648/article/details/131530227
今日推荐