LeetCode-072中,最后一步的转移方程是做什么?
摘要:本题在线练习:LeetCode 72. 编辑距离 - 在线练习(免费 · 无需登录 · AI 辅助)(https:onefly.topzero2Leetcodeplayground
本题在线练习:LeetCode 72. 编辑距离 - 在线练习(免费 · 无需登录 · AI 辅助)(https://onefly.top/zero2Leetcode/playground.html?id=72)
配套刷题网站 Zero2Leetcode —— 内置本地 OJ + AI 教练,零门槛开始刷 Hot 100。
题目概述
给定两个字符串 word1 和 word2,每次操作可以:
插入一个字符
删除一个字符
替换一个字符
求把 word1 变成 word2 的最少操作数,这就是经典的编辑距离(Levenshtein distance)。
核心思路:dp[i][j] 表示把前缀变成前缀的最小代价
设 dp[i][j] 表示把 word1[:i] 变成 word2[:j] 的最小编辑距离。
边界:
dp[0][j] = j:空串变成长度为 j 的串,只能插入 j 次
dp[i][0] = i:长度为 i 的串变成空串,只能删除 i 次
转移看“最后一步”:
如果 word1[i-1] == word2[j-1],最后一个字符不用动:
dp[i][j] = dp[i-1][j-1]
如果不相等,最后一步可能是三种操作之一:
替换:把 word1[i-1] 替换成 word2[j-1],代价 dp[i-1][j-1] + 1
删除:删除 word1[i-1],代价 dp[i-1][j] + 1
插入:在 word1 末尾插入 word2[j-1],代价 dp[i][j-1] + 1
取最小:
dp[i][j] = 1 + min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1])
代码实现(二维 dp)
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = i
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:
dp[i][j] = 1 + min(
dp[i - 1][j - 1], # 替换
dp[i - 1][j], # 删除
dp[i][j - 1], # 插入
)
return dp[m][n]
逐行拆解:三种操作为什么对应这三个格子
把 word1[:i] 变成 word2[:j]:
替换:先把 word1[:i-1] 变成 word2[:j-1],再替换最后一个字符
删除:先把 word1[:i-1] 变成 word2[:j],再删除 word1 的最后一个字符
插入:先把 word1[:i] 变成 word2[:j-1],再插入 word2 的最后一个字符
对应的就是 dp[i-1][j-1]、dp[i-1][j]、dp[i][j-1] 三个位置。
手动模拟:word1="horse", word2="ros"
最终答案为 3,一条可能的最优路径:
horse -> rorse(把 h 替换成 r)
rorse -> rose(删除一个 r)
rose -> ros(删除 e)
DP 表的作用是:不需要手工找路径,直接计算出最小代价。
复杂度分析
时间:O(mn)
空间:O(mn)(如果需要,可以滚动数组优化到 O(n))
总结
编辑距离的转移看似复杂,但只要抓住一句话就稳了:
dp[i][j] 的来源,就是“最后一步”可能做了替换/删除/插入三种操作之一。
把这三种操作对应到三个相邻格子,转移方程就不需要背。
