NLP中有个 编辑距离 的概念,常运用到单词纠错中。本博文介绍并代码实现 编辑距离。参考并综合以下三篇博文。
- https://blog.csdn.net/LWHGMAN/article/details/100067314
- https://blog.csdn.net/baodream/article/details/80417695
- https://www.jianshu.com/p/a617d20162cf
代码思路
# 1)首先考虑A串的第一个字符
#
# 假设存在两个字符串A和B,他们的长度分别是lenA和lenB。首先考虑第一个字符,由于他们是一样的,所以只需要计算A[2...lenA]和B[2...lenB]之间的距离即可。
# 那么如果两个字符串的第一个字符不一样怎么办?可以考虑把第一个字符变成一样的(这里假设从A串变成B串):
#
# 修改A串的第一个字符成B串的第一个字符,之后仅需要计算A[2...lenA]和B[2...lenB]的距离即可;
# 删除A串的第一个字符,之后仅需要计算A[2...lenA]和B[1...lenB]的距离即可;
# 把B串的第一个字符插入到A串的第一个字符之前,之后仅需要计算A[1...lenA]和B[2...lenB]的距离即可。
# 2)接下来考虑A串的第i个字符和B串的第j个字符。
#
# 我们这个时候不考虑A的前i-1字符和B串的第j-1个字符。如果A串的第i个字符和B串的第j个字符相等,即A[i]=B[j],则只需要计算A[i...lenA]和B[j...lenB]之间的距离即可。如果不想等,则:
#
# 修改A串的第i个字符成B串的第j个字符,之后仅需要计算A[i+1...lenA]和B[j+1...lenB]的距离即可;
# 删除A串的第i个字符,之后仅需要计算A[i+1...lenA]和B[j...lenB]的距离即可;
# 把B串的第j个字符插入到A串的第i个字符之前,之后仅需要计算A[i...lenA]和B[j+1...lenB]的距离即可。
# 写到这里,自然会想到用递归求解或者动态规划求解,由于用递归会产生很多重复解,所以用动态规划。
递归代码:
oldarr=list('kittenkitten')
newarr=list('sittingsitting')
def fun(arrA,arrB,i,j):
if i ==len(arrA) or j==len(arrB):
return len(arrA)+len(arrB)-i-j
else:
if arrA[i]==arrB[j]:
return fun(arrA,arrB,i+1,j+1)
else:
return min(fun(arrA,arrB,i+1,j)+1,fun(arrA,arrB,i,j+1)+1,fun(arrA,arrB,i+1,j+1)+1) #删除 插入 替换
print fun(oldarr,newarr,0,0)
动态规划代码:
#动态规划
# 关键在于建立二维矩阵,这时,要分清i和j分别代表什么含义。矩阵中的数字,代表什么含义。
# 总结:i和j代表两个可以相对遍历的序列长度,矩阵中的数字代表目标函数的值。
#比如:i=1 和j=2时候,表示old序列只考虑到长度是1,而目标序列,假设只考虑到长度是2
oldarr=list('kittenkitten')
newarr=list('sittingsitting')
def funDynamic(oldarr,newarr):
arrValue = []
lenI = len(oldarr) + 1
lenJ = len(newarr) + 1
for i in range(lenI):
arrValue.append([0] * lenJ)
for i in range(lenI):
for j in range(lenJ):
if i==0 or j==0:
arrValue[i][j] = i+j
continue
if oldarr[i-1]==newarr[j-1]:
d = 0
else:
d = 1
# 分别对应:插入、删除、替换 操作
arrValue[i][j] =min(arrValue[i - 1][j] + 1, arrValue[i][j-1] + 1, arrValue[i-1][j-1] + d)
for i in range(lenI):
print arrValue[i]
print arrValue[lenI-1][lenJ-1]
funDynamic(oldarr,newarr)