最短编辑距离

写给对问题有了解的人

从一个例子开始(Leetcode72)
a = 'horse', b= 'row'
从a变成b最短需要几步?
输出: 3
解释: 
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

从上面的解释我们可以知道什么?
看第一步,将 'h' 替换为 'r'。
- 是否可以直接删除h呢?显然可以。
- 是否可以在h前面插入r呢?当然也行。
- 将h替换成r呢?也是可以的。

选择很多,哪个选择更好呢?分别使用三种方法做一次改变,然后递归下去。
比较三种方法需要的最小次数就行了
作为动态规划的经典题目,先写递归再转移方程
递归

以下陈述的前提是将a变成b

  • 如果a[i] == b[i]。如a = 'one', b='ohe',计算a='ne'b=‘he’的编辑距离就行.
  • 如果a[i] != b[i],比较三种方法需要的最短编辑距离就行
    • 插入法,插入后可保证a[i] == b[i],此时需要计算a[i:]b[i+1:]的编辑距离。如a='abc', b='dbc',先将a变成'dabc',然后比较a='abc'b='bc'的编辑距离。当然具体编程的时候不需要真的插入元素,只需要将结果加上1就行了
    • 删除法。老规矩,a='abc', b='dbc',将a变成bc,然后比较a='bc'b=‘dbc’的编辑距离
    • 替换法。a='abc', b='dbc'。将a变成'dbc',比较a='bc’和b='bc’的编辑距离即可

综上所述,递归方程为
f ( a , b ) = { f ( a [ i + 1 : ] , b [ i + 1 : ] ) a[i]=b[i] m i n ( f ( a , b [ i + 1 : ] ) , f ( a [ i + 1 : ] , b ) , f ( a [ i + 1 : ] , b [ i + 1 : ] ) ) + 1 a[i]!=b[i] l e n ( a ) len(b)==0 l e n ( b ) len(a)==0 f(a, b) = \begin{cases} f(a[i+1:], b[i+1:])& \text{a[i]=b[i]}\\ min( f( a, b[i+1:]), f(a[i+1:], b), f(a[i+1:], b[i+1:]) )+1& \text{a[i]!=b[i]}\\ len(a)& \text{len(b)==0}\\ len(b)& \text{len(a)==0} \end{cases} f(a,b)=f(a[i+1:],b[i+1:])min(f(a,b[i+1:]),f(a[i+1:],b),f(a[i+1:],b[i+1:]))+1len(a)len(b)a[i]=b[i]a[i]!=b[i]len(b)==0len(a)==0

Python代码
def editdistance(a, b):
    if not a:     # 条件四
        if not b:
            return 0
        return len(b)
    if not b:  # 条件三
        if not a:
            return 0
        return len(a)
    for i in range(len(b)):
        if a[i] == b[i]:   # 条件一
            return editdistance(a[i+1:], b[i+1:])
        else:  # 条件二
            # 删除、插入、替换
            delete = 1 + editdistance(a[i+1:], b[i:])
            insert = 1 + editdistance(a[i:], b[i+1:])
            replace = 1 + editdistance(a[i+1:], b[i+1:])
            return min(delete, insert, replace)

但是递归的时间复杂度是让人难以忍受的

动态规划

有了递归,动态规划的代码就好写了
附上一个LeetCode72自己已经AC的代码

class Solution:
    def minDistance(self, a: str, b: str) -> int:
        if not a:
            if not b:
                return 0
            return len(b)
        if not b:
            if not a:
                return 0
            return len(a)
        
        row, col = len(a), len(b)
        DP = [[0 for _ in range(col+1)] for _ in range(row+1)]
        for i in range(1, col+1):
            DP[0][i] = i
        for i in range(1, row+1):
            DP[i][0] = i
        
        for i in range(1, row+1):
            for j in range(1, col+1):
                if a[i-1] == b[j-1]:
                    DP[i][j] = DP[i-1][j-1]
                else:
                    DP[i][j] = min(DP[i-1][j-1], DP[i][j-1], DP[i-1][j]) + 1
        return DP[-1][-1]

在这里插入图片描述
代码很简单,把
DP[i][j] = min(DP[i-1][j-1], DP[i][j-1], DP[i-1][j]) + 1
拿出来说一下,这个对应的相当于条件二

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值