动态规划----编辑距离
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')
提示:
0 <= word1.length, word2.length <= 500
word1 和 word2 由小写英文字母组成
2 分析
2.1 暴力递归
最值问题---->dp
涉及到两个字符串---->二维dp, dp[i][j]
step1 定义dp[i][j]
dp[i][j] 表示将单词word1[0:i]转换成word2[0:j]所使用的最小操作数
step2 base case
dp[0][j] 当word1已经遍历完时,将wrod2的剩余字符添加到word1中即可。求取操作数,直接返回剩余word2长度即可。
dp[i][0] 当word2已经遍历完时,将word1的剩余字符删除即可。求取操作数,直接返回剩余word1长度即可。
step3 递推关系(最优子结构)
dp(i, j) = dp(i + 1, j + 1) 跳过 (word1[i] == word2[j]) 不采取任何操作,计数不增加
= min(
dp(i + 1, j) + 1 删除 (word1[i] != word2[j], j 不变,将word1[i] 删除,即i指针向前移动一位)
dp(i , j + 1) + 1 插入 (word1[i] != word2[j], i 不变,将字符插入word1中。即word2[j]匹配插入字符,j指针向前移动一位)
dp(i + 1, j + 1) + 1 替换 (word1[i] != word2[j], 将word1[i] 替换为word2[j], 当前位置匹配,同时向前移动两个指针)
)
代码:
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
def dp(i,j):
# 从底到顶,暴力递归。
# base case
if i == len(word1) and j == len(word2):
return 0
if i == len(word1):
return len(word2) - j
if j == len(word2):
return len(word1) - i
# 递推关系
if word1[i] == word2[j]:
return dp(i + 1, j + 1)
else:
return min(dp(i + 1, j), dp(i, j + 1), dp(i + 1, j + 1)) + 1
return dp(0, 0)
2.2 暴力递归 + 优化重复子问题
分析:从递推关系式 或者 画个树状图 可以看出存在重复子问题,通过备忘录 或 dp table 优化重复子问题
备忘录
将所有返回值更新在备忘录 memo 中,dp 函数最后返回 memo[i][j] 即可
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
# 因为初始化所有值为-1,因为查询 i == len(word1) 时查询了 memo[i][j],所以长度为memo[m+1][n+1]
memo = [[-1 for j in range(len(word2) + 1)] for i in range(len(word1) + 1)]
def dp(i,j):
if memo[i][j] != -1:
return memo[i][j]
if i == len(word1) and j == len(word2):
memo[i][j] = 0
return memo[i][j]
if i == len(word1):
memo[i][j] = len(word2) - j
return memo[i][j]
if j == len(word2):
memo[i][j] = len(word1) - i
return memo[i][j]
if word1[i] == word2[j]:
memo[i][j] = dp(i + 1, j + 1)
else:
memo[i][j] = min(dp(i + 1, j), dp(i, j + 1), dp(i + 1, j + 1)) + 1
return memo[i][j]
return dp(0, 0)
dp table
已知边界条件,直接先初始化边界条件。并从边界条件开始递推目标值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)