算法|Day48 动态规划16

LeetCode 583- 两个字符串的删除操作

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

题目描述:给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数

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

解题思路

  1. 确定dp数组(dp table)以及下标的含义

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,最少删除dp[i][j]个元素,可以得到相同的字符串。

  1. 确定递推公式

首先分两种情况,当前字符相等不相等,若相等,则直接dp[i][j] = dp[i-1][j-1]表示我们不用执行任何操作。

若不相等,则需要分三种情况

    • 首先是删除第一个字符串中的字符,也就是dp[i-1][j]+1
    • 其次有可能我们要删除第二个字符串中的元素,也就是dp[i][j-1]+1
    • 再有可能我们两个字符串的元素都要删除一个,也就是dp[i-1][j-1]+2

故递推公式我们可以简化为dp[i][j] = min({dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+2});

  1. dp数组如何初始化

dp[i][0] 表示以下标i-1为结尾的字符串和空串相等所需要操作的最少步数,故应该是i,故dp[i][0]=i, dp[0][j]同理。

  1. 确定遍历顺序

依据递推公式我们可以看出,dp[i][j]是由左边和左上的以及上面的状态推出的,所以我们从上至下,从左向右遍历即可。

  1. 举例推导dp数组
class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1));
        for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
        for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
        for (int i = 1; i <= word1.size(); i++) {
            for (int j = 1; j <= word2.size(); j++) {
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }
};

总结:

  • 这题可以省略dp[i-1][j-1]+2这种情况,因为这种情况我们已经在别的情况里讨论到了,也就是dp[i-1][j]+1是删除i,dp[i][j-1]是删除j,两个各执行一次就包含了这种情况了。

LeetCode 72- 编辑距离

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

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

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

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

解题思路

1.确定dp数组(dp table)以及下标的含义

dp[i][j]:代表字符串1以i-1下标为结尾的部分和字符串2以j-1为结尾的部分,转换所需要的最小操作数。

2.确定递推公式

我们需要分情况讨论,首先字符串1与字符串2当前字符相等或不等的情况,

  • 相等,则不进行操作。也就是dp[i][j] = dp[i-1][j-1]
  • 不相等时又有三种操作,删除第一个字符串中的字符删除第二个字符串中的字符或修改其中一个字符(这样就可以使得这两个字符在下标范围内通过这些操作可以成相同的了)。故我们又取最小值,故dp[i][j] = min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]}) + 1

这里我们不用考虑插入元素,为什么呢?因为插入就相当于是添加元素,如果我们删除第一个字符串的一个字符,就等同于给第二个字符串添加一个元素。

3.dp数组如何初始化

首先dp[i][0]代表的是第一个字符串从i-1下标开始,第二个字符串为空串时,操作最少步骤,使得两个字符串相等。故我们全部只需要删除即可,也就是i步即可。dp[0][j]同理。

4.确定遍历顺序

依据递推公式我们可以看出,dp[i][j]是由左边和左上的以及上面的状态推出的,所以我们从上至下,从左向右遍历即可。

5.举例推导dp数组

class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1 = word1.size();
        int len2 = word2.size();
        vector<vector<int>> dp(len1+1,vector<int>(len2+1,0));
        for(int j=0;j<=len2;j++)dp[0][j] = j;
        for(int i=0;i<=len1;i++)dp[i][0] = i;
        for(int i=1;i<=len1;i++){
            for(int j=1;j<=len2;j++){
                if(word1[i-1] == word2[j-1]){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = min({dp[i-1][j-1],dp[i-1][j],dp[i][j-1]})+1;
                }
            }
        }
        return dp[len1][len2];
    }
};

总结:

  • 本题关键还是要理解dp数组的含义,要将其牢记在心,这样才能真正弄懂一道题。这题主要难点就是对于两个字符串进行操作的时候的情况讨论。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值