导语
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 <= 500word1和word2只包含小写英文字母
解法
使用动规五部曲:
- dp数组含义:dp[i][j]表示以i-1为结尾的word1,和以j-1为结尾的word2的最小删除操作次数;
- 递推公式:
# 如果两个字符相同,那么不需要进行任何操作
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数组:略
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 <= 500word1和word2由小写英文字母组成
解法
使用动规五部曲:
- dp数组含义:dp[i][j]表示以i-1为结尾的word1,以j-1为结尾的word2的最小编辑距离;
- 递推公式:
- 当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)
- 初始化:考虑如何将一个非空字符串删除变为一个空字符串,所以可得
- 遍历顺序:从前向后,从上向下
- 打印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]