幾種距離的基礎研究上——編輯距離

一、編輯距離(Levenshtein距離)

簡介

這個距離是1965年一個戰斗名族叫Levenshtein的一個發明的一個算法。

這個所謂的距離,實際是指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數。這些編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符。

維基百科

中文維基:快戳我;

英文維基:英文不好別戳我

基本原理

算法就是簡單的線性動態規劃(最長上升子序列就屬于線性動態規劃)。

設我們要將s1變成s2

定義狀態矩陣edit[len1][len2],len1和len2分別是要比較的字符串s1和字符串s2的長度+1(+1是考慮到動歸中,一個串為空的情況)

然后,定義edit[i][j]是s1中前i個字符組成的串,和s2中前j個字符組成的串的編輯距離

具體思想是,對于每個i,j從0開始依次遞增,對于每一次j++,由于前j-1個字符跟i的編輯距離已經求出,所以只用考慮新加進來的第j個字符即可

插入操作:在s1的前i個字符后插入一個字符ch,使得ch等于新加入的s2[j]。于是插入字符ch的編輯距離就是edit[i][j-1]+1

刪除操作:刪除s1[i],以期望s1[i-1]能與s2[j]匹配(如果s1[i-1]前邊的幾個字符能與s2[j]前邊的幾個字符有較好的匹配,那么這么做就能得到更好的結果)。另外,對于s1[i-1]之前的字符跟s2[j]匹配的情況,edit[i-1][j]中已經考慮過。于是刪除字符ch的編輯距離就是edit[i-1][j]+1

替換操作:期望s1[i]與s2[j]匹配,或者將s1[i]替換成s2[j]后匹配。于是替換操作的編輯距離就是edit[i-1][j-1]+f(i,j)。其中,當s1[i]==s2[j]時,f(i,j)為0;反之為1

于是動態規劃公式如下:

if i == 0 且 j == 0,edit(i, j) = 0

if i == 0 且 j > 0,edit(i, j) = j

if i > 0 且j == 0,edit(i, j) = i

if 0 < i ≤ 1 且 0 < j ≤ 1 ,edit(i, j) == min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) },當第一個字符串的第i個字符不等于第二個字符串的第j個字符時,f(i, j) = 1;否則,f(i, j) = 0。


上面的描述并不形象,換個圖形化表示:

下圖為計算字符“beauty”與“batyu”編輯距離的二維圖解:

圖1

圖2

步驟詳解:

幾點說明:

(1) 坐標軸垂直向下為x軸正向,水平向右為y軸正向。因此紅圈1的坐標為(1,1),紅圈2的坐標為(1,2)。

(2) 這個矩陣中的點含義是兩個字符要經過多少編輯操作才能完成轉換。編輯操作就是上面的3類操作。

(3) 在更新矩陣中距離的時候,對應參照的向量中表示左側(相當于上面講到的刪除操作)和上測(相當于上面講到的插入操作)的值,不論它對應的字母是否相同,左側和上測向量值均加1。

推算步驟:

(1) 先建立一張二維表(矩陣),如上圖所示。矩陣中(0,0)位置不對應字母。

(2) 計算矩陣(1,1)位置(即:紅圈1所在的置)的值,此處為方便描述,將該位置定義為A點。

A點的值需要由A點左上方、左邊和上邊的值共同決定。為方便描述先將A點所需要的三個值賦給向量a,則a=(0,1,1)。A點對應的字母分別為(b,b),字母相同,則A點左上角的值加0(不同則加1),A點左邊與上邊的值分別加1。此時a=(0,2,2),取a中做小值填入A點位置,見右圖所示。

計算矩陣(1,2)位置(即:紅圈2所在的位置),定義為B點。B點對應向量為b=(1,0,2)。由于B點對應的字母為(b,e),字母不同,則B點左上角的值加1,同時,B點左側上側分別加1。此時b=(2,1,3),取b中最小值賦給B點。

(3) 按照步驟2)求出每個格子中的值。所有值求出后,右下角的值為最小編輯距離。

Python實現

這里給出了一個別人實現的代碼,同時,有人指出了它的缺陷,再此進行了修正。

#!/user/bin/env python  
# -*- coding: utf-8 -*-  
  
class Levenshtein(object):  
      
    def __init__(self):  
        pass
     
    def get_distance(self,first,second):  
        """編輯距離的求算過程。"""
        
        # 如果字符串1的長度大于字符串2的長度,則交換兩個字符串。
        if len(first) > len(second):  
            first,second = second,first
        # 如果兩個字符串中有一個是空串,則另一個串可以通過字符串長度轉換為該串(刪除或者插入字符)。
        if len(first) == 0:  
            return len(second)  
        if len(second) == 0:  
            return len(first)  
        
        first_length = len(first) + 1  
        second_length = len(second) + 1 
        
        # 初始化基礎字符串
        distance_matrix = [[0 for y in range(second_length)] for x in range(first_length)]
        # 初始化x軸初值
        for x in range(first_length):
            distance_matrix[x][0] = x
        # 初始化y軸初值
        for y in range(second_length):
            distance_matrix[0][y] = y
        
        # 開始計算距離 
        for i in range(1,first_length):  
            for j in range(1,second_length):  
                del_edtion = distance_matrix[i-1][j] + 1  
                ins_edtion = distance_matrix[i][j-1] + 1  
                sub_edtion = distance_matrix[i-1][j-1]  
                if first[i-1] != second[j-1]:  
                    sub_edtion += 1  
                distance_matrix[i][j] = min(ins_edtion,del_edtion,sub_edtion)   
        return distance_matrix[first_length-1][second_length-1]  
      
if __name__ == "__main__":  
    leven_obj = Levenshtein()  
    print leven_obj.get_distance('beauty','batyu')

結果矩陣

[0, 1, 2, 3, 4, 5, 6]
[1, 0, 1, 2, 3, 4, 5]
[2, 1, 1, 1, 2, 3, 4]
[3, 2, 2, 2, 2, 2, 3]
[4, 3, 3, 3, 3, 3, 2]
[5, 4, 4, 4, 3, 4, 3]

參考文獻(排名不分先后)

  1. "使用最小編輯距離算法求字符串相似度"
  2. "最小編輯距離_Python"
  3. "字符串相似性算法【最長公共字符串算法】 【LCS】"
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,771評論 0 33
  • 分治方法 將問題劃分成互不相交的子問題 遞歸地求解子問題 將子問題的解組合起來 動態規劃(兩個要素:最優子結構、子...
    superlj666閱讀 516評論 0 0
  • 動態規劃(Dynamic Programming) 本文包括: 動態規劃定義 狀態轉移方程 動態規劃算法步驟 最長...
    廖少少閱讀 3,336評論 0 18
  • thiele插值算法 1點插值算法 function [C,c]=thiele(X,Y,Z)%X為插值點橫坐標,Y...
    00crazy00閱讀 2,045評論 0 4
  • 無意間看到了有人問編輯距離算法,當時對這個概念很陌生,也就去學習了下,做下總結,記錄下,好記性不如爛筆頭。 編輯距...
    辣條閱讀 3,983評論 0 0