1. 程式人生 > 其它 >演算法題(2) Levenshtein編輯距離

演算法題(2) Levenshtein編輯距離

技術標籤:演算法題

Levenshtein編輯距離

  問題描述:在應用領域中,經常會遇到對兩個字串進行比較的問題,比如在自然語言處理中,需要比較兩個句子的相似度,高階點的方法有神經網路、TF-IDF文字相似度等,最基礎的方法就是編輯距離了,最初它是由俄羅斯科學家Vladimir Levenshtein在1965年提出來的。它的解釋是給定一個原字串和一個目標字串,計算將原字串修改為目標字串時所編輯的最小次數。編輯可以是“增加”、“刪除”和“修改”三種。

  思路:本題需要動態規劃思想,即對兩個長字串分別由小到大“部分計算”,直到最後完成全部的編輯。首先我們建立一個表格(可以用二維陣列儲存),其規格為(m+1)×(n+1),m、n分別為兩個字串的長度。我們假設原字串是“kitten”,目標字串是“sitting”,將原字串設定為橫向表頭,將目標字串設定為縱向表頭(也可以反過來設定),則我們建立一個7×8的表格,如下所示:

<\b>kitten
<\b>
s
i
t
t
i
n
g

  表格建立完成後,我們開始編輯距離演算法。

1、初始化: 首先我們對錶格執行初始化,方法是將<\b>所對應的每一行、列都從0開始,置為遞增的整數,即0,1,2…m或n. 如下圖:

Edit-Dist<\b>kitten
<\b>0123456
s1
i2
t3
t4
i5
n6
g7

  解釋:表格中的數字表示當前步驟時所編輯的次數,由於我們設定橫向為原字串,縱向為目標字串,因此<\b>行的數字代表刪除操作,<\b>列的部分代表插入操作。比如"kitten"中的"e"所對應的數字"5",指的是在編輯時先將"kitten"中的“kitte”刪除時的5個刪除操作;“sitting”中的"n"對應的“6”代表編輯時先插入“sittin”時的6次插入操作。

2、填充表格: 接下來我們填充表格剩餘的空白部分,方法如下:首先比較當前位置Matrix[i][j]所對應的列頭、行頭的字元是否相同,相同則當前位置取Matrix[i][j-1]+1、Matrix[j][i-1]+1和Matrix[i-1][j-1]的最小值,否則取Matrix[i][j-1]+1、Matrix[j][i-1]+1和Matrix[i-1][j-1]+1的最小值。如下圖:

Edit-Dist<\b>kitten
<\b>0123456
s1123456
i2212345
t3321234
t4432123
i5543223
n6654332
g7765443

  解釋:由Matrix[i][j-1]至Matrix[i][j]的為插入操作,由Matrix[i-1][j]至Matrix[i][j]的為刪除操作,由Matrix[i-1][j-1]至Matrix[i][j]的為修改操作(字元相同時不必修改,編輯步數不改變)。

3、最小編輯距離:
  我們通過Levenshtein距離演算法對錶格實現了填充,編輯距離為表格最右下角的數字。因此"kitten"到"sitting"的最小編輯距離是3.

  下面我們展示Levenshtein編輯距離的Python實現程式碼:

class solution:

    def __init__(self, source, target):
        self.source = source
        self.target = target
        self.Matrix = []
        self.edit_distance(self.source, self.target)

    def edit_distance(self, source, target):
        if len(target) == 0 and len(source) == 0:
            return 0
        row = []
        for i in range(len(target)+1):
            row.append(i)
            for j in range(len(source)):
                if i == 0 :
                    row.append(j+1)
                    continue
                row.append(0)
            self.Matrix.append(row)
            row=[]
        for i in range(1, len(target)+1):
            for j in range(1, len(source)+1):
                if target[i-1] == source[j-1] : edit = 0
                else : edit = 1
                self.Matrix[i][j] = min(self.Matrix[i-1][j]+1, self.Matrix[i][j-1]+1, self.Matrix[i-1][j-1]+edit)
        for i in range(len(target)+1):
            print(self.Matrix[i])



if __name__ == '__main__':
    edit = solution('kitten','sitting')

  程式碼可以輸出編輯狀態矩陣。執行結果如下:
在這裡插入圖片描述

  :字串的編輯距離都是對稱的,即字串A到字串B的最小編輯距離也是字串B到字串A的最小編輯距離。如果我們在程式碼中將“kitten”和“sitting”的位置互換,則編輯狀態矩陣變為原矩陣的轉置。