算法介紹:
編輯距離(Edit Distance),又稱Levenshtein距離,是指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數。許可的編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符。
算法原理:
設我們可以使用d[ i , j ]個步驟(可以使用一個二維數組保存這個值),表示將串s[ 1…i ] 轉換為 串t [ 1…j ]所需要的最少步驟個數,那么,在最基本的情況下,即在i等於0時,也就是說串s為空,那么對應的d[0,j] 就是 增加j個字符,使得s轉化為t,在j等於0時,也就是說串t為空,那么對應的d[i,0] 就是 減少 i個字符,使得s轉化為t。
然后我們考慮一般情況,加一點動態規划的想法,我們要想得到將s[1..i]經過最少次數的增加,刪除,或者替換操作就轉變為t[1..j],那么我們就必須在之前可以以最少次數的增加,刪除,或者替換操作,使得現在串s和串t只需要再做一次操作或者不做就可以完成s[1..i]到t[1..j]的轉換。所謂的“之前”分為下面三種情況:
1)我們可以在k個操作內將 s[1…i] 轉換為 t[1…j-1]
2)我們可以在k個操作里面將s[1..i-1]轉換為t[1..j]
3)我們可以在k個步驟里面將 s[1…i-1] 轉換為 t [1…j-1]
針對第1種情況,我們只需要在最后將 t[j] 加上s[1..i]就完成了匹配,這樣總共就需要k+1個操作。
針對第2種情況,我們只需要在最后將s[i]移除,然后再做這k個操作,所以總共需要k+1個操作。
針對第3種情況,我們只需要在最后將s[i]替換為 t[j],使得滿足s[1..i] == t[1..j],這樣總共也需要k+1個操作。而如果在第3種情況下,s[i]剛好等於t[j],那我們就可以僅僅使用k個操作就完成這個過程。
最后,為了保證得到的操作次數總是最少的,我們可以從上面三種情況中選擇消耗最少的一種最為將s[1..i]轉換為t[1..j]所需要的最小操作次數。
算法實現步驟:
步驟
說明
1
設置n為字符串s的長度。("GUMBO")
設置m為字符串t的長度。("GAMBOL")
如果n等於0,返回m並退出。
如果m等於0,返回n並退出。
構造兩個向量v0[m+1] 和v1[m+1],串聯0..m之間所有的元素。
2
初始化 v0 to 0..m。
3
檢查 s (i from 1 to n) 中的每個字符。
4
檢查 t (j from 1 to m) 中的每個字符
5
如果 s[i] 等於 t[j],則編輯代價cost為 0;
如果 s[i] 不等於 t[j],則編輯代價cost為1。
6
設置單元v1[j]為下面的最小值之一:
a、緊鄰該單元上方+1:v1[j-1] + 1
b、緊鄰該單元左側+1:v0[j] + 1
c、該單元對角線上方和左側+cost:v0[j-1] + cost
7
在完成迭代 (3, 4, 5, 6) 之后,v1[m]便是編輯距離的值。
算法步驟詳解:
本小節將演示如何計算"GUMBO"和"GAMBOL"兩個字符串的Levenshtein距離。
步驟1、2
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
A
2
M
3
B
4
O
5
L
6
初始化完了之后重點是理解步驟6.
步驟3-6,當 i = 1
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
0
A
2
1
M
3
2
B
4
3
O
5
4
L
6
5
我們算V1中的值:以紅色的0所在的格子為例根據步驟5:
如果 s[i] 等於 t[j],則編輯代價cost為 0;
如果 s[i] 不等於 t[j],則編輯代價cost為1。
和
步驟6: 設置單元v1[j]為下面的最小值之一:
a、緊鄰該單元上方+1:v1[j-1] + 1
b、緊鄰該單元左側+1:v0[j] + 1
c、該單元對角線上方和左側+cost:v0[j-1] + cost
得到:
a: 該格子所在上方為 1加上1為2 b:該格子左邊為1加上1為2 c:該格子對角線上方和左側(也就是左斜對角)為0+ cost(cost是通過步驟5得到的編輯花費,這里G等於G所以編輯花費為0,cost為0) 為0
三個值中 最小的為0,則 該格子的值為0
其他格子以此類推。
步驟3-6,當 i = 2
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
0
1
A
2
1
1
M
3
2
2
B
4
3
3
O
5
4
4
L
6
5
5
步驟3-6,當 i = 3
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
0
1
2
A
2
1
1
2
M
3
2
2
1
B
4
3
3
2
O
5
4
4
3
L
6
5
5
4
步驟3-6,當 i = 4
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
0
1
2
3
A
2
1
1
2
3
M
3
2
2
1
2
B
4
3
3
2
1
O
5
4
4
3
2
L
6
5
5
4
3
步驟3-6,當 i = 5
v0
v1
G
U
M
B
O
0
1
2
3
4
5
G
1
0
1
2
3
4
A
2
1
1
2
3
4
M
3
2
2
1
2
3
B
4
3
3
2
1
2
O
5
4
4
3
2
1
L
6
5
5
4
3
2
步驟7
編輯距離就是矩陣右下角的值,v1[m] == 2。由"GUMBO"變換為"GAMBOL"的過程對於我來說是很只管的,即通過將"A"替換為"U",並在末尾追加"L"這樣子(實際上替換的過程是由移除和插入兩個操作組合而成的)。
我們得到最小編輯距離為2
那么它們的相似度為 (1-ld/(double)Math.max(str1.length(), str2.length()));
1 - 2/6=0.6666666666666667