返回

动态规划理解LeetCode 72: 编辑距离问题

闲谈

动态规划深入理解:编辑距离与 LeetCode 72

导语:

编辑距离是一个关键概念,在自然语言处理和数据挖掘等领域有着广泛的应用。LeetCode 72 挑战我们计算将一个字符串转换为另一个字符串所需的最小编辑操作数。动态规划提供了一种优雅的解决方案,本文将深入探讨其工作原理。

什么是编辑距离?

编辑距离衡量两个字符串之间的差异程度,表示将一个字符串转换为另一个字符串所需的最小编辑操作数,包括:

  • 插入: 添加一个字符
  • 删除: 移除一个字符
  • 替换: 用一个字符替换另一个字符

动态规划算法

动态规划将问题分解为子问题,逐步求解。对于编辑距离问题,我们定义二维数组 dp,其中 dp[i][j] 表示将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最小操作数。

dp 数组的计算遵循以下公式:

dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + (word1[i] == word2[j] ? 0 : 1))
  • 第一句表示插入操作
  • 第二句表示删除操作
  • 第三句表示替换操作(如果字符相同,不需要操作)

通过逐行逐列计算 dp 数组,最终得到 dp[word1.length][word2.length],即最小编辑操作数。

示例

给定 word1 = "horse"word2 = "ros",我们逐步计算 dp 数组:

dp = [
  [0, 1, 2, 3, 4, 5],
  [1, 0, 1, 2, 3, 4],
  [2, 1, 0, 1, 2, 3],
  [3, 2, 1, 0, 1, 2],
  [4, 3, 2, 1, 0, 1],
  [5, 4, 3, 2, 1, 0]
]
dp[1][0] = 1 (插入)
dp[2][0] = 2 (插入)
...
dp[5][5] = 3 (替换)

因此,将 "horse" 转换为 "ros" 需要 3 次编辑操作。

Python 代码示例

def edit_distance(word1, word2):
  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):
      insert_cost = dp[i-1][j] + 1
      delete_cost = dp[i][j-1] + 1
      replace_cost = dp[i-1][j-1] + (word1[i-1] != word2[j-1])
      dp[i][j] = min(insert_cost, delete_cost, replace_cost)

  return dp[m][n]

结论

动态规划是解决编辑距离问题的强大工具。它将问题分解成子问题,并以高效的方式计算整体解决方案。本指南提供了对算法的深入理解,并辅以示例和代码片段,供您更好地掌握其工作原理。

常见问题解答

1. 编辑距离有其他应用吗?
是的,编辑距离广泛应用于拼写检查、机器翻译和生物信息学。

2. 动态规划算法是否总是能找到最佳解决方案?
是的,动态规划算法保证找到最优解决方案。

3. 如何优化动态规划算法以提高性能?
空间优化技术,如滚动数组,可以显著提高空间复杂度。

4. 除了插入、删除和替换之外,编辑距离还可以包含其他操作吗?
是的,可以扩展算法以包括其他操作,如反转或移位。

5. 编辑距离和最小编辑序列有什么关系?
编辑距离是计算最小编辑序列的必要步骤,该序列表示将一个字符串转换为另一个字符串所需的具体编辑操作。