day59 动态规划part16

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

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

每步 可以删除任意一个字符串中的一个字符。

示例 1:

输入: word1 = “sea”, word2 = “eat”
输出: 2
解释: 第一步将 “sea” 变为 “ea” ,第二步将 "eat "变为 “ea”
示例 2:

输入:word1 = “leetcode”, word2 = “etco”
输出:4

方法一:

在这里插入图片描述

方法二:

上述解决方案是套用了「最长公共子序列(LCS)」进行求解,最后再根据 LCS 长度计算答案。

而更加契合题意的状态定义是根据「最长公共子序列(LCS)」的原始状态定义进行微调:定义 f[i][j]f[i][j]f[i][j] 代表考虑 s1s1s1 的前 iii 个字符、考虑 s2s2s2 的前 jjj 个字符(最终字符串不一定包含 s1[i]s1[i]s1[i] 或 s2[j]s2[j]s2[j])时形成相同字符串的最小删除次数。
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        //dp[i][j]代表考虑 s1s1s1 的前 iii 个字符、考虑 s2s2s2 的前 jjj 个字符(最终字符串不一定包含 s1[i]s1[i]s1[i] 或 s2[j]s2[j]s2[j])时形成相同字符串的最小删除次数
        int[][] dp = new int[len1 + 1][len2 + 1];  

        // 初始化,当其中一个为空字符时,另一个要想变成空字符必须删除 i 次
        for (int i = 0; i <= len1; i++) { // 注意这里是小于等于,不要弄丢等于
            dp[i][0] = i;
        }
        for (int i = 0; i <= len2; i++) {
            dp[0][i] = i;
        }

        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 - 1][j] + 1, dp[i][j - 1] + 1);
                }
            }
        }
        return dp[len1][len2];
    }
}

72. 编辑距离

中等
相关标签
相关企业
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:

输入:word1 = “horse”, word2 = “ros”
输出:3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
示例 2:

输入:word1 = “intention”, word2 = “execution”
输出:5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)

难点:

这里dp【i】【j】表示使原字符串在【0,i-1】和【0,j-1】区间相同需要的最小操作数,侧面反应,经过dp后,即dp数组被赋值后,所赋值的区间内字符串完全相同,举个例子,dp【4】【5】 = 5,说明在区间【0,3】和【0,4】两字符串完全相同,需要的最小操作数为5。简言之,dp过后区间内字符串相同。

此时我们在回过头来看递推公式,如果i-1和j-1对应的字符相同,此时无须操作,继承将【0,i-2】和【0,j-2】变成相同的最小操作数,即dp【i】【j】 = dp【i-1】【j-1】,注意此时【0,i-2】和【0,j-2】区间经过操作后字符串完全相同(即使我们没有真的对原字符串进行任何操作);
如果二者不相等,此时一定要对某个字符进行操作(增删改,注意增和删的效果等效),假设我们删除i-1对应的元素,此时相同字符区间由【0,i-1】和【0,j-1】变成了【0,i-2】和【0,j-1】(注意此时该区间内的dp已经被赋值,说明该区间内的字符串已经完全相同),操作数也在此基础上加一,删j-1同理;我们考虑改变其中一个元素使二者相同,则我们在区间【0,i-2】和【0,j-2】的基础上加一即可。

总而言之,dp过后的区间内,其字符串已经完全相同,可以直接拿过来用。
在这里插入图片描述

class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int 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(Math.min(dp[i][j - 1] + 1, dp[i - 1][j] + 1), dp[i - 1][j - 1] + 1);
                }
            }
        }

        return dp[len1][len2];
    }
}
  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值