【动态规划】力扣72:编辑距离

给你两个单词 word1 和 word2,请返回将 word1 转换成 word2 所使用的最少操作数  。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例:

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

编辑距离算法被数据科学家广泛应用,是用作机器翻译和语音识别评价标准的基本算法。
最直观的方法是暴力检查所有可能的编辑方法,取最短的一个。所有可能的编辑方法达到指数级,但我们不需要进行这么多计算,因为我们只需要找到距离最短的序列而不是所有可能的序列。
image

  1. 定义 dp[i][j]
  • dp[i][j] 代表 word1 中前 i 个字符,变换到 word2 中前 j 个字符,最短需要操作的次数;
  • 需要考虑 word1 或 word2 一个字母都没有,即全增加/删除的情况,所以预留 dp[0][j] 和 dp[i][0]。
  1. 状态转移
    image
    image
  • 增,修改消耗dp[i][j] = dp[i][j - 1] + 1
  • 删,dp[i][j] = dp[i - 1][j] + 1
  • 改,dp[i][j] = dp[i - 1][j - 1] + 1
  • 如果刚好这两个字母相同 word1[i - 1] = word2[j - 1] ,那么可以直接参考 dp[i - 1][j - 1] ,操作不用加一。
    按顺序计算,当计算 dp[i][j] 时,dp[i - 1][j] , dp[i][j - 1] , dp[i - 1][j - 1] 均已经确定了。配合增删改这三种操作,需要对应的 dp 把操作次数加1,取三种的最小。
    image
class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        m, n = len(word1), len(word2)
        if m * n == 0: # 至少有一个字符串为空串
            return m + n
        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数组的定位差1
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
        return dp[m][n]

时间复杂度 :O(mn),其中 m 为 word1 的长度,n 为 word2 的长度。
空间复杂度 :O(mn),需要大小为 O(mn) 的 dp 数组来记录状态值。

posted @   Vonos  阅读(148)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示