算法介紹:

編輯距離(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