[Algorithmic Toolbox学习笔记][week5]Edit distance

问题描述

假设我们有以下两组strings:

A = "1468"
B = "4769"

如果我们想把A变成B,即想把 “1468” 变成 “4769” ,对于string A我们最少需要几步操作?
这个操作包含 删除插入替换。

可以发现A和B中都有数字4和6,那么我们可以保留下4,6,只针对1,8做处理
具体操作流程如下

所以我们的算法需要求:如果要把A变成B,那么在A上我们最少要进行几次操作
即我们要计算针对string A的Edit distance。

算法思路解析

由上面可以知道,要将 string A变成 string B,可能的操作有以下四种:

删除从A中删除掉多余的元素对应上图中红色列1 次操作
插入在A中添加缺失的元素对应上图中蓝色列1 次操作
替换将A中的元素替换为B对应上图中紫色列1 次操作
不进行任何操作对应上图中绿色列0 次操作

假设 i 为string A的最后一个字符的索引,j 为string B的最后一个字符的索引。我们从两个strings的最后一个字符开始看。

case1 - 替换

 

如果i位置的字符要被替换为j位置的字符:
那么我们实际上只需要求A [1 ... i-1] 变成 B[1 ... j-1] 所需要的最小操作次数。然后再在此次数上再加1(因为替换i and j要算作是一次操作)。那么我们可以知道:

D[ i ][ j ] = D[ i - 1 ][ j - 1 ] +1

case2 - 无操作

 

如果i位置的字符和j位置的字符相同
那么我们实际上只需要求A [1 ... i-1] 变成 B[1 ... j-1] 所需要的最小操作次数(此时我们不需要加1,因为字符相同的时候不需要进行任何操作)。那么我们可以知道:

D[ i ][ j ] = D[ i - 1 ][ j - 1 ]

case3 - 删除

 

如果i位置的字符是多余的需要被删除:
那么我们实际上只需要求A [1 ... i-1] 变成 B[1 ... j] 所需要的最小操作次数。然后再在此次数上再加1(因为删除要算作是一次操作)。那么我们可以知道:

D[ i ][ j ] = D[ i - 1 ][ j ] +1

case4 - 插入

 

如果我们需要插入一个字符:
那么我们实际上只需要求A [1 ... i] 变成 B[1 ... j-1] 所需要的最小操作次数。然后再在此次数上再加1(因为插入要算作是一次操作)。那么我们可以知道:

D[ i ][ j ] = D[ i ][ j - 1 ] +1

案例说明:

以下圆圈中需要填入坐标对应的A变成B所需要的最小操作次数。

比如,图中红色圈圈表示数组将数组 A = “” 变成数组 B = “476” 所需要的最小操作次数。
那么我们知道将空数组变成476需要新增3个数,因此最少也需要3次操作,所以圆圈内填入3。

那么针对第一行和第一列,要把空字符串变成一个字符串,或把一个字符串变成一个空字符串需要的操作次数等于字符的个数,填入数字后我们可以得到:

  

要求上图中红圈中的数字坐标(1,1),即求 1 变成 4 需要的次数,有以下几种方式:

情况前置操作当前操作当前操作次数
情况1A中新增4删除1D(0,1) + 1 = 1+1 = 2
情况2A中删除1

新增4

D(1,0) + 1 = 1+1 = 2
情况3将1替换为4D(0,0) + 1 = 0+1 = 1

由上面的表格我们可以知道最少操作次数为1,那么通过这个表格我们同样可以知道要求一个坐标对应的值我们实际上求其前置情况的最小操作次数+1,即:

因此要求下图中红色圆圈D(2,1)中的值,我们只需要看蓝色圆圈中的数字即可。此时,由于D(0,2)和D(0,1)都等于4,因此最小值就等于D(1,0)

根据此逻辑将圆圈中的数字完善,我们可以得到下面的图片。 绿色箭头表示新增操作,红色箭头表示删除操作,黄色箭头表示没有操作,蓝色箭头表示替换操作。

 

Implementation

# in python3
def edit_distance(A,B):
    a = len(A)
    b = len(B)
    D = [[0 for x in range(b+1)] for x in range(a+1)] #用于获取一个坐标轴

    for i in range(a+1):
        for j in range(b+1):
            if i == 0:
                D[i][j] = j #当stringA为空时,将B中所有字符插入到A
            elif j == 0:
                D[i][j] = i #当stringB为空时,从A中删除掉所有字符
            elif A[i-1] == B[j-1]:
                D[i][j] = D[i-1][j-1]
            else:
                D[i][j] = 1 + min(D[i-1][j-1], D[i-1][j], D[i][j-1])

    return D[a][b]

A = "key"
B = "yesterday"
print(edit_distance(A,B))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值