算法学习day56

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

1.1 题目描述

题目描述:

给定两个单词word1和word2,找到使得word1和word2相同所需要的的最小步数,每步可以删除任意一个字符串的一个字符。

例:

输入:“sea”,“eat”

输出:2

解释:第一步将"sea"变为"ea",第二步将“eat”变成“ea”

1.2分析

1.确定dp数组以及下标含义

dp[i] [j] :以i-1为结尾的字符串word1和以j-1位结尾的字符串word2,想要达到相同,所需要删除元素的最少次数。

2.确定递推公式

(1)当word1[i-1]与word2[j-1]相同的时候

dp[i] [j] = dp[i - 1] dp[j-1]

(2)当word1[i-1]与word2[j-1]不相同的时候

​ (2.1)删word1[i-1],最少操作次数为dp[i-1] [j] + 1

​ (2.2)删word2[j-1],最少操作次数为dp[i] [j-1] +1

​ (2.3)同时删除word1[i-1]和word2[j-1],操作的最少次数为dp[i-1] [j-1]+2

取最小值,得递推公式:dp[i] [j] = min(min(dp[i-1] [j-1]+2,dp[i-1] [j]+1), dp[i] [j-1] + 1)

3.dp数组如何初始化

dp[i] [0]:word2为空字符串,以i-1为结尾的字符串word1需要删除多少个元素,才能和word2相同?显然dp[i] [0] = i

dp[0] [j]同理:

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;

4.确定遍历顺序

从上到下,从左到右。

5.举例推导dp数组
在这里插入图片描述

1.3 代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        // 创建动态规划数组,行数为 word1 的长度加一,列数为 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;  // 当 word2 为空时,将 word1 中的所有字符都删除,需要的操作数为 i
        for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;  // 当 word1 为空时,将 word2 中的所有字符都插入到 word1 中,需要的操作数为 j
        
        // 递推计算 dp 数组中的其他元素
        for (int i = 1; i <= word1.size(); i++) {
            for (int j = 1; j <= word2.size(); j++) {
                if (word1[i - 1] == word2[j - 1]) {
                    // 如果 word1 的第 i 个字符和 word2 的第 j 个字符相同,那么将不需要进行操作
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    // 当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
                    // 取这三种操作的最小值
                    dp[i][j] = min(min(dp[i-1][j-1]+2,dp[i-1][j]+1), dp[i][j-1] + 1);
                }
            }
        }
        
        // 返回 dp 数组的最后一个元素,即将 word1 转换为 word2 需要的最少操作数
        return dp[word1.size()][word2.size()];
    }
};

2.力扣72. 编辑距离

2.1 题目描述

题目描述:

给你两个单词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’)

2.2 分析

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

dp[i] [j]表示以下标i-1为结尾的字符串word1和以下标j-1为结尾的字符串word2,最近的编辑距离为dp[i] [j].

2.确定递推公式

if(word1[i-1] == word23[j-1])
    不操作
if(word1[i-1] !=word2[j-1])
    增
    删
    换

如上所视,一共四种情况:

if(word1[i-1] == word23[j-1])说明不需要任何操作,递推公式:dp[i] [j] = dp[i-1] [j-1]

if(word1[i-1] !=word2[j-1]):

(1) word1删除一个元素,那么就是以下标i-2为结尾的word1与j-1为结尾的word2的最近编辑距离再加上一个操作。

dp[i] [j] = dp[i-1] [j] + 1

(2)word2删除一个元素,那么就是以下标i-1为结尾的word1与j-2为结尾的word2的最近编辑距离在加上一个操作。

dp[i] [j] =dp[i] [j-1] + 1

(3)替换元素,word1替换word1[i-1],使其与word2[j-1]相同。

dp[i] [j] =dp[i-1] [j-1] +1

综上取最小得递推公式:dp[i] [j] = min(min(dp[i-1] [j-1],dp[i-1] [j]),dp[i] [j-1]) + 1;

3.dp数组如何初始化

dp[i] [j]:表示以下标i-1为结尾的字符串word1和以下标j-1为结尾的字符串成word2,最近的编辑距离为dp[i] [j].

dp[i] [0]:以下标i-1为结尾的字符串word1和空字符串word2,最近编辑距离为dp[i] [0].

dp[i] [0]表示对word1里的元素全部做删除操作,dp[i] [0] = i;

同理:

dp[0] [j] = j;

for(int i = 0 ; i<= word1.size(); i++) dp[i] [0] = i;
for(int j = 0; j <=word2.size(); j++) dp[0] [j] = j;

4.确定遍历顺序

从上到下,从左到右。

5.举例推导dp数组

在这里插入图片描述

2.3 代码

class Solution {
public:
    int minDistance(string word1, string word2) {
        // 创建一个二维数组来存储最小编辑距离
        // dp[i][j]表示将word1的前i个字符转换成word2的前j个字符所需的最小编辑距离
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
        
        // 初始化第一行和第一列,分别表示将一个字符串转换为空字符串所需的最小编辑距离
        for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
        for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
        
        // 计算dp数组中的其他值
        for (int i = 1; i <= word1.size(); i++) {
            for (int j = 1; j <= word2.size(); j++) {
                // 如果word1的第i个字符等于word2的第j个字符
                // 则不需要进行任何操作,编辑距离等于dp[i-1][j-1]
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
                // 如果word1的第i个字符不等于word2的第j个字符
                // 则有三种操作:插入、删除、替换
                // 插入:dp[i][j-1]表示将word1的前i个字符转换成word2的前j-1个字符的最小编辑距离
                // 删除:dp[i-1][j]表示将word1的前i-1个字符转换成word2的前j个字符的最小编辑距离
                // 替换:dp[i-1][j-1]表示将word1的前i-1个字符转换成word2的前j-1个字符的最小编辑距离
                // 由于需要对word1进行操作,因此操作数需要加1
                else {
                    dp[i][j] = min(min(dp[i-1][j-1],dp[i-1][j]),dp[i][j-1]) + 1;
                }
            }
        }
        // 返回将word1的所有字符转换成word2的所有字符所需的最小编辑距离
        return dp[word1.size()][word2.size()];
    }
};

3.参考资料

[代码随想录]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值