python 编辑距离_编辑距离python实现及内存优化

本文详细介绍了编辑距离算法,用于量化两个字符串之间的差异,并探讨了其在文本相似度、输入纠错等场景的应用。文章讨论了不同定义下的编辑距离,包括替换字符时的距离设定,并给出了Python库的使用示例。同时,通过递归和动态规划两种方法实现算法,重点优化了动态规划的内存消耗,最后提出了进一步的时间效率优化思路。
摘要由CSDN通过智能技术生成

编辑距离

编辑距离(Edit Distance 或者 Levenshtein Distance)是为了量化两个字符串之间的差异,简单来说就是将一个字符串改成另一个字符串最少需要多少步

举个栗子

有一个字符串 a='love',b='lolpe'.那么计算a和b的编辑距离,就是要算出从a变化到 b需要经过多少个步骤。

1.love->lolve(插入l)

2.lolve->lolpe(用v替换成p)

那么我们就说他们的编辑距离为2

应用场景

从ssmetic的层面计算文本相似度

输入纠错 等等

定义公式

定义如下Edit Distance Defination

这里a_i不等于b_j时,增加的距离d=1

但是我在斯坦福的课程里看到的定义是这里加的是2

这里d=1修改成了d=2,是为了区分替换字符串与增删字符串的距离

如果不改变

假设字符串a='love',b='sffg',c='lovefghaa' 那么如果我们用上面计算出a和b,c的距离:

lev(a,b)=4,lev(a,c)=5

a跟b的距离小于a跟c的距离,显然不合理

所以实践中会采用下面这种定义

但是下面leetcode的题目里是用的第一种定义(d=1)

相关python库

那么如果不想自己写算法的话

可以偷懒使用以下库

python中的类库:pip install python-Levenshteindistance(str1, str2),计算编辑鲁丽

hamming(str1, str2),计算长度相等的字符串str1和str2的汉明距离

ratio(str1, str2),计算莱文斯坦比。计算公式 r = (sum – ldist) / sum, 其中sum是指str1 和 str2 字串的长度总和,ldist是类编辑距离。注意这里是类编辑距离,在类编辑距离中删除、插入依然+1,但是替换+2。

jaro(str1, str2)

jaro_winkler(str1, str2)

python实现方法

leetcode 题目链接

https://leetcode-cn.com/problems/edit-distance/

有两种思路,一种是递归,一种是动态规划

递归可以理解为倒推的,动态规划可以理解为正推

递归的自调用可能会超出限制,动态规划需要的内存比较多

递归方法

递归的方法在leetcode中会输出超出限制

很明显字符串超长的时候并不能使用递归

递归方法代码如下

class Solution(object):

def minDistance(self, word1, word2):

""":type word1: str:type word2: str:rtype: int"""

print(word1, word2)

if word1 == word2:

print('a=b')

return 0

elif (len(word2) == 0 )or (len(word1) == 0):

return max(len(word1),len(word2))

if word1[-1] == word2[-1]:

d = 0

else:

d = 2

return min(

self.minDistance(word1[:-1],word2) +1,

self.minDistance(word1,word2[:-1]) +1,

self.minDistance(word1[:-1],word2[:-1]) + d,

)

动态规划

我一开始是这么写的

def minDistance(word1, word2):

"""

:type word1: str

:type word2: str

:rtype: int

"""

#注意这里的矩阵行列

matrix = [[ i + j for j in range(wl_2 + 1)] for i in range(wl_1 + 1)]

for i in range(1,wl_1 +1):

for j in range(1,wl_2+1):

if word1[i-1] == word2[j-1]:

d = 0

else:

d = 1

matrix[i][j] = min(

matrix[i][j-1] +1,

matrix[i-1][j] +1,

matrix[i-1][j-1] + d

)

return matrix[-1][-1]

很明显这个虽然跑通了,但是排名是非常的amazing啊感人

显然有很多优化的空间

最容易优化的一开始就列出一些简单比较的情况

比如word1跟word2相同或者word1/word2中至少有一个为空的情况

def minDistance(word1, word2):

"""

:type word1: str

:type word2: str

:rtype: int

"""

if word1 == word2:

return 0

# 增加一点小小的限制

wl_1 = len(word1)

wl_2 = len(word2)

if wl_1==0 or lwl_2 ==0:

return max(wl_1, wl_2)

matrix = [[ i + j for j in range(wl_2 + 1)] for i in range(wl_1 + 1)]

for i in range(1,wl_1 +1):

for j in range(1,wl_2+1):

if word1[i-1] == word2[j-1]:

d = 0

else:

d = 1

matrix[i][j] = min(

matrix[i][j-1] +1,

matrix[i-1][j] +1,

matrix[i-1][j-1] + d

)

return matrix[-1][-1]

结果非常的amazing啊,时间一下就少了500+ms,所以细节非常重要显然还是不大行

但是还是很菜

但是经过我们精妙的观察

每次计算编辑距离的时候其实只涉及了当前计算的前一行数据

每次循环用到的数据范围如图

以此类推

所以我们根本不需要存整个matrix,只需要存两行数据就行

魔改后代码如下

class Solution(object):

def minDistance(self, word1, word2):

"""

:type word1: str

:type word2: str

:rtype: int

"""

if word1 == word2:

return 0

wl_1 = len(word1)

wl_2 = len(word2)

if wl_1==0 or wl_2 ==0:

return max(wl_1, wl_2)

v1, v2 = [], []

for i in range(wl_2+1):

v1.append(i), v2.append(i+1)

for i in range(1,wl_1 +1):

for j in range(1,wl_2+1):

if word1[i - 1] == word2[j - 1]:

d = 0

else:

d = 1

minValue = min( v1[j] + 1,

v1[j - 1] + d ,

v2[j-1] + 1,

)

v2[j] = minValue

for j in range(wl_2 + 1):

v1[j] = v2[j]

v2[j] = i+1

return v1[-1]

修改后的代码内存消耗骤降内存方面已经成为王者了,但是在时间消耗方面还可以优化下

怎么减少时间我还没有想好QAQ

等我想好了再来更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值