最小編輯距離或萊文斯坦距離(Levenshtein),指由字符串A轉化為字符串B的最小編輯次數。允許的編輯操作有:刪除,插入,替換。具體內容可參見:維基百科—萊文斯坦距離。一般代碼實現的方式都是通過動態規劃算法,找出從A轉化為B的每一步的最小步驟。從Google圖片借來的圖,
Python代碼實現, (其中要注意矩陣的下標從1開始,而字符串的下標從0開始):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
def normal_leven(str1, str2): len_str1 = len (str1) + 1 len_str2 = len (str2) + 1 #create matrix matrix = [ 0 for n in range (len_str1 * len_str2)] #init x axis for i in range (len_str1): matrix[i] = i #init y axis for j in range ( 0 , len (matrix), len_str1): if j % len_str1 = = 0 : matrix[j] = j / / len_str1 for i in range ( 1 , len_str1): for j in range ( 1 , len_str2): if str1[i - 1 ] = = str2[j - 1 ]: cost = 0 else : cost = 1 matrix[j * len_str1 + i] = min (matrix[(j - 1 ) * len_str1 + i] + 1 , matrix[j * len_str1 + (i - 1 )] + 1 , matrix[(j - 1 ) * len_str1 + (i - 1 )] + cost) return matrix[ - 1 ] |
最近看文章看到Python庫提供了一個包difflib實現了從對象A轉化對象B的步驟,那么計算最小編輯距離的代碼也可以這樣寫了:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def difflib_leven(str1, str2): leven_cost = 0 s = difflib.SequenceMatcher( None , str1, str2) for tag, i1, i2, j1, j2 in s.get_opcodes(): #print('{:7} a[{}: {}] --> b[{}: {}] {} --> {}'.format(tag, i1, i2, j1, j2, str1[i1: i2], str2[j1: j2])) if tag = = 'replace' : leven_cost + = max (i2 - i1, j2 - j1) elif tag = = 'insert' : leven_cost + = (j2 - j1) elif tag = = 'delete' : leven_cost + = (i2 - i1) return leven_cost |