编辑距离(Edit Distance)
字数 1522 2025-11-21 23:21:15
编辑距离(Edit Distance)
我将为您详细讲解编辑距离(Edit Distance)这个经典的线性动态规划问题。
问题描述
给定两个字符串 word1 和 word2,计算将 word1 转换成 word2 所需的最少操作次数。允许的操作包括:
- 插入一个字符
- 删除一个字符
- 替换一个字符
示例:
- 输入:word1 = "horse", word2 = "ros"
- 输出:3
- 解释:horse → rorse (将 'h' 替换为 'r'),rorse → rose (删除 'r'),rose → ros (删除 'e')
解题思路
第一步:定义状态
我们定义 dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最少操作次数。
i的范围:0 到len(word1)j的范围:0 到len(word2)
边界情况:
dp[0][j] = j:将空字符串转换为word2的前j个字符,需要j次插入操作dp[i][0] = i:将word1的前i个字符转换为空字符串,需要i次删除操作
第二步:状态转移方程
对于每个位置 (i, j),我们考虑三种操作:
-
如果字符相等:
word1[i-1] == word2[j-1]- 不需要操作,直接继承前一个状态:
dp[i][j] = dp[i-1][j-1]
- 不需要操作,直接继承前一个状态:
-
如果字符不相等:我们有三种选择:
- 插入:在
word1中插入word2[j-1],然后匹配word1[0:i]和word2[0:j-1]- 操作次数:
dp[i][j-1] + 1
- 操作次数:
- 删除:删除
word1[i-1],然后匹配word1[0:i-1]和word2[0:j]- 操作次数:
dp[i-1][j] + 1
- 操作次数:
- 替换:将
word1[i-1]替换为word2[j-1],然后匹配word1[0:i-1]和word2[0:j-1]- 操作次数:
dp[i-1][j-1] + 1
- 操作次数:
- 插入:在
因此,状态转移方程为:
如果 word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
否则:
dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
第三步:具体计算过程
以 word1 = "horse", word2 = "ros" 为例:
初始化 dp 表:
"" "r" "ro" "ros"
"" 0 1 2 3
"h" 1
"ho" 2
"hor"3
"hors"4
"horse"5
逐步填充表格:
i=1, j=1: 'h' vs 'r' → 不相等 → min(1,1,0)+1 = 1i=1, j=2: 'h' vs 'ro' → 不相等 → min(2,1,1)+1 = 2i=1, j=3: 'h' vs 'ros' → 不相等 → min(3,2,2)+1 = 3i=2, j=1: 'ho' vs 'r' → 不相等 → min(2,1,1)+1 = 2i=2, j=2: 'ho' vs 'ro' → 'o'=='o' → dp[1][1] = 1i=2, j=3: 'ho' vs 'ros' → 不相等 → min(2,1,2)+1 = 2- 继续这个过程...
最终得到的 dp 表:
"" "r" "ro" "ros"
"" 0 1 2 3
"h" 1 1 2 3
"ho" 2 2 1 2
"hor"3 2 2 2
"hors"4 3 3 3
"horse"5 4 4 3
第四步:代码实现
def minDistance(word1, word2):
m, n = len(word1), len(word2)
# 初始化dp表
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
# 填充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:
dp[i][j] = min(
dp[i][j - 1], # 插入
dp[i - 1][j], # 删除
dp[i - 1][j - 1] # 替换
) + 1
return dp[m][n]
第五步:复杂度分析
- 时间复杂度:O(m × n),其中 m 和 n 分别是两个字符串的长度
- 空间复杂度:O(m × n),可以使用滚动数组优化到 O(min(m, n))
第六步:实际应用
编辑距离在现实生活中有广泛应用:
- 拼写检查和自动更正
- DNA序列比对
- 自然语言处理中的相似度计算
- 版本控制系统中的文件差异比较
这个算法通过动态规划优雅地解决了字符串转换的最小代价问题,是理解线性动态规划的经典范例。