Leetcode刷题笔记56:动态规划16(583. 两个字符串的删除操作-72. 编辑距离)

100 阅读3分钟

导语

leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:

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

题目描述

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

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

 

示例 1:

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

示例  2:

输入: word1 = "leetcode", word2 = "etco"
输出: 4

 

提示:

  • 1 <= word1.length, word2.length <= 500
  • word1 和 word2 只包含小写英文字母

解法

使用动规五部曲:

  1. dp数组含义:dp[i][j]表示以i-1为结尾的word1,和以j-1为结尾的word2的最小删除操作次数;
  2. 递推公式:
                # 如果两个字符相同,那么不需要进行任何操作
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    # 如果两个字符不同,我们有以下几种操作方式:
                    # 1. 删除 word1 的一个字符(dp[i-1][j] + 1)
                    # 2. 删除 word2 的一个字符(dp[i][j-1] + 1)
                    # 我们选择这两种方式中最小的一种
                    dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)
  1. 初始化:考虑如何将一个非空字符串删除变为一个空字符串,所以可得dp[i][0]=i,dp[0][j]=jdp[i][0]=i,dp[0][j]=j
  2. 遍历顺序:从前向后,从上向下
  3. 打印dp数组:略
class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        # m, n 分别为两个单词的长度
        m, n = len(word1), len(word2)
        
        # 初始化一个动态规划表格 dp,大小为 (m+1) x (n+1)
        # dp[i][j] 将存储 word1 的前 i 个字符与 word2 的前 j 个字符相同所需的最小步数
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        
        # 初始化第一列:将 word1 变为空字符串需要的步骤数
        for i in range(m + 1):
            dp[i][0] = i
            
        # 初始化第一行:将 word2 变为空字符串需要的步骤数
        for j in range(n + 1):
            dp[0][j] = j
            
        # 开始填充动态规划表格
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                # 如果两个字符相同,那么不需要进行任何操作
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    # 如果两个字符不同,我们有以下几种操作方式:
                    # 1. 删除 word1 的一个字符(dp[i-1][j] + 1)
                    # 2. 删除 word2 的一个字符(dp[i][j-1] + 1)
                    # 我们选择这两种方式中最小的一种
                    dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)
        
        # 最终的答案存储在 dp[m][n] 中
        return dp[m][n]

Leetcode 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')

 

提示:

  • 0 <= word1.length, word2.length <= 500
  • word1 和 word2 由小写英文字母组成

解法

使用动规五部曲:

  1. dp数组含义:dp[i][j]表示以i-1为结尾的word1,以j-1为结尾的word2的最小编辑距离;
  2. 递推公式:
    • 当word1[i-1]==word2[j-1]时,那么dp[i][j]=dp[i-1][j-1]
    • 当word1[i-1]!=word2[j-1]时,那么我们可以通过删除word1或者word2的末尾字符,或者直接替换word1/word2的最后一个字符变为相等,增加的操作可以由字符数量多的转换为删除字符变为字符数量少的,因此,这里dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1)
  3. 初始化:考虑如何将一个非空字符串删除变为一个空字符串,所以可得dp[i][0]=i,dp[0][j]=jdp[i][0]=i,dp[0][j]=j
  4. 遍历顺序:从前向后,从上向下
  5. 打印dp数组:略

完整代码如下:

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        # 初始化两个单词的长度为 m 和 n
        m, n = len(word1), len(word2)
        
        # 创建一个动态规划矩阵 dp,其大小为 (m+1) x (n+1)
        # dp[i][j] 表示从 word1 的前 i 个字符到 word2 的前 j 个字符所需要的最少操作数
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        
        # 初始化第一列:将 word1 转换为一个空字符串所需的步数
        for i in range(m + 1):
            dp[i][0] = i
            
        # 初始化第一行:将一个空字符串转换为 word2 所需的步数
        for j in range(n + 1):
            dp[0][j] = j
            
        # 使用两个嵌套循环填充整个 dp 矩阵
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                # 如果当前比较的两个字符相等,则不需要进行任何操作
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    # 否则,我们可以执行以下三种操作之一:
                    # 1. 删除一个字符(dp[i-1][j] + 1)
                    # 2. 插入一个字符(dp[i][j-1] + 1)
                    # 3. 替换一个字符(dp[i-1][j-1] + 1)
                    # 我们取这三个操作中最小的一个
                    dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 1)
                    
        # dp[m][n] 存储了从 word1 转换为 word2 所需的最少操作数
        return dp[m][n]