动态规划专题 (III):Leetcode 72 编辑距离

动态规划专题 (III):Leetcode 72 编辑距离

Leetcode 72 编辑距离

题目描述

给定两个单词 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')

题解

编辑距离是最小的改变次数 这句话是这个题目的核心

整个递归式是这样的:(分三种情况)对于当前字母 word1[i]word2[j] 来说。

  1. 如果当前两个字母相匹配,那这个字符就不会改变,因此对这个问题就满足:
    E d i t ( w o r d 1 , w o r d 2 ) = E d i t ( w o r d 1 [ 0 : i − 1 ] , w o r d 2 [ 0 : i − 1 ] ) Edit(word1, word2)=Edit(word1[0 : i-1], word2[0 : i-1]) Edit(word1,word2)=Edit(word1[0:i1],word2[0:i1])
  2. 若两个字母不匹配,那这个字符就会产生改变,但是改变有三种方式:
    1. word1 插入一个元素,对应的:
      E d i t ( w o r d 1 , w o r d 2 ) = E d i t ( w o r d 1 [ 0 : i − 1 ] , w o r d 2 [ 0 : i ] ) + 1 Edit(word1, word2)=Edit(word1[0 : i-1], word2[0 : i])+1 Edit(word1,word2)=Edit(word1[0:i1],word2[0:i])+1
    2. word2 插入一个元素
      E d i t ( w o r d 1 , w o r d 2 ) = E d i t ( w o r d 1 [ 0 : i ] , w o r d 2 [ 0 : i − 1 ] ) + 1 Edit(word1, word2)=Edit(word1[0 : i], word2[0 : i-1])+1 Edit(word1,word2)=Edit(word1[0:i],word2[0:i1])+1
    3. 改变一个元素
      E d i t ( w o r d 1 , w o r d 2 ) = E d i t ( w o r d 1 [ 0 : i − 1 ] , w o r d 2 [ 0 : i − 1 ] ) + 1 Edit(word1, word2)=Edit(word1[0 : i-1], word2[0 : i-1])+1 Edit(word1,word2)=Edit(word1[0:i1],word2[0:i1])+1

之前提到了说,编辑距离是最小的改变次数 因此这个问题的核心就是在字符不相同的时候,找以上三种情况的最小值。

因此转化为递归式就有了网上经常能看到的转移方程。

{ d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] if word1[i]=word2[j] d p [ i ] [ j ] = min ⁡ { d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] } + 1 if word1[i]  ≠  word2[j] \begin{cases} dp[i][j] = dp[i-1][j-1] & \text{if word1[i]=word2[j]}\\ dp[i][j] = \min\{dp[i-1][j],dp[i][j-1],dp[i-1][j-1]\}+1 & \text{if word1[i] $\ne$ word2[j]} \end{cases} {dp[i][j]=dp[i1][j1]dp[i][j]=min{dp[i1][j],dp[i][j1],dp[i1][j1]}+1if word1[i]=word2[j]if word1[i] = word2[j]

对于边界情况,左上角一定是0,将这个字符串扩充为:

word1 = " " + word1
word2 = " " + word2

假设这两个字符串为 "horse""ros" 那这个矩阵为:

[ ⋱ "   " h o r s e "   " 0 r o s ] \left[\begin{matrix} \ddots&"\text{ }"&h&o&r&s&e\\ "\text{ }"&0\\ r\\ o\\ s \end{matrix}\right] " "ros" "0horse

因为 word1word2 的第 ij 不可能是 " ",因此根据上面的式子,可以推出:

d p [ i ] [ j ] = min ⁡ { d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] } dp[i][j]= \min\{dp[i-1][j],dp[i][j-1],dp[i-1][j-1]\} dp[i][j]=min{dp[i1][j],dp[i][j1],dp[i1][j1]}

因此这个矩阵初始化为:

[ ⋱ "   " h o r s e "   " 0 1 2 3 4 5 r 1 o 2 s 3 ] \left[\begin{matrix} \ddots&"\text{ }"&h&o&r&s&e\\ "\text{ }"&0&1&2&3&4&5\\ r&1\\ o&2\\ s&3\\ \end{matrix}\right] " "ros" "0123h1o2r3s4e5

可以发现,初始化横纵第一列、行一定是一个连续从 0 递增的序列。因此按照转移方程,最终结果在矩阵的右下角得到

整个代码如下:

class Solution(object):
    def minDistance(self, word1, word2):
        word1 = " " + word1
        word2 = " " + word2
        matrix = [[None for j in word2] for i in word1]
        n = len(word1)
        m = len(word2)
        # Initialize
        for i in range(0, n):
            matrix[i][0] = i
        for j in range(0, m):
            matrix[0][j] = j
        for i in range(1, n):
            for j in range(1, m):
                if word1[i] == word2[j]:
                    matrix[i][j] = matrix[i-1][j-1]
                else:
                    # 分别为:替换一个,word1插入一个,word2插入一个
                    matrix[i][j] = min(matrix[i-1][j-1], matrix[i-1][j], matrix[i][j-1]) + 1
        return matrix[-1][-1]

执行结果

执行时间:108 ms

内存消耗:14.9 MB

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值