編輯距離 Edit distance

2021-07-22 09:57:52 字數 2773 閱讀 2517

**

插入乙個字元,例如:fj -> fxj

刪除乙個字元,例如:fxj -> fj

替換乙個字元,例如:jxj -> fyj

用分治的思想解決比較簡單,將複雜的問題分解成相似的子問題

假設字串 a, 共 m 位,從a[1]a[m]

字串 b, 共 n 位,從b[1]b[n]

d[i][j]表示字串a[1]-a[i]轉換為b[1]-b[j]的編輯距離

那麼有如下遞迴規律(a[i] 和 b[j] 分別是字串 a 和 b 的最後一位):

a[i]等於b[j]時,d[i][j] = d[i-1][j-1], 比如 fxy -> fay 的編輯距離等於 fx -> fa 的編輯距離

a[i]不等於b[j]時,d[i][j]等於如下 3 項的最小值:

d[i-1][j] + 1(刪除a[i]), 比如 fxy -> fab 的編輯距離 = fx -> fab 的編輯距離 + 1

d[i][j-1] + 1(插入b[j]), 比如 fxy -> fab 的編輯距離 = fxyb -> fab 的編輯距離 + 1 = fxy -> fa 的編輯距離 + 1

d[i-1][j-1] + 1(將a[i]替換為b[j]), 比如 fxy -> fab 的編輯距離 = fxb -> fab 的編輯距離 + 1 = fx -> fa 的編輯距離 + 1

遞迴邊界:

**

按照上面的思路將**寫下來

int edit_distance(char *a, char *b, int i, int j)

else

if (i == 0) else

if (a[i-1] == b[j-1]) else

}edit_distance(stra, strb, strlen(stra), strlen(strb));

但是有個嚴重的問題,就是**的效能很低下,時間複雜度是指數增長的

上面的**中,很多相同的子問題其實是經過了多次求解,解決這類問題的辦法是用動態規劃

用動態規劃思想優化時間複雜度

像以上解決思路,是從後往前算的,比如我想知道edit_distance(a, b, i, j)我可能需要知道edit_distance(a, b, i-1, j-1)

有一種想法不錯,就是從前往後算,先算出各個子問題,然後根據子問題,計算出原問題, 對於這個問題效能不錯,而且也挺容易理解,下面就來說一說

例如以字串 a = 「fxy」, b = 「fab」 為例

首先建立乙個矩陣,用來存放子問題及原問題的編輯距離,並將遞迴邊界在矩陣中填好,如下:

然後計算 i = 1, j = 1 所對應的編輯距離:比較 a[i] 和 b[j] 是否相等然後根據遞迴規律算出這個值

比如在這種情況下 a[i] = f 和 b[j] = f, 那麼 d[i][j] 就等於 d[i-1][j-1] 等於 0

然後計算 i = 1, j = 2 直到算出 i = 3, j = 3, 原問題的編輯距離就等於 d[3][3]

最終矩陣如下:

現在的時間複雜度已到了可接受範圍,為 o(mn)

**如下:

int edit_distance(char *a, char *b)

for (j = 0; j <= lenb; j++)

for (i = 1; i <= lena; i++) else }}

return d[lena][lenb];

}

這個演算法的空間複雜度為 o(mn), 當一步步填寫矩陣的過程中,應該能夠感受到, 空間複雜度可以繼續優化,因為計算矩陣的時候總是需要有限的量,同一時間並不需要所有矩陣的值

根據具體問題優化空間複雜度

還是以 a = 「fxy」, b = 「fab」 為例,例如計算 d[1][3], 也就是下圖中的綠色方塊, 我們需要知道的值只需 3 個,下圖中藍色方塊的值

進一步分析,我們知道,當計算 d[1] 這行的時候,我們只需知道 d[0] 這行的值, 同理我們計算當前行的時候只需知道上一行就可以了

再進一步分析,其實我們只需要一行就可以了,每次計算的時候我們需要的 3 個值, 其中上邊和左邊的值我們可以直接得到,坐上角的值需要臨時變數(如下**使用 old)來記錄

**如下:

int edit_distance(char *a, char *b)

for (i = 1; i <= lena; i++) else

old = temp;}}

return d[lenb];

}

寫**的過程中需要注意的一點就是,當一行計算好之後開始下一行的時候, 要初始化 old 和 d[0] 的值

優化過後時間複雜度還是 o(mn), 空間複雜度降低了,以上**是 o(n), 其實很簡單可以寫成 o(min(m,n)), 為了便於理解,就不具體寫了

編輯距離及編輯距離演算法

編輯距離概念描述 編輯距離,又稱levenshtein距離,是指兩個字串之間,由乙個轉成另乙個所需的最少編輯操作次數。許可的編輯操作包括將乙個字元替換成另乙個字元,插入乙個字元,刪除乙個字元。例如將kitten一字轉成sitting sitten k s sittin e i sitting g 俄...

編輯距離及編輯距離演算法

include include include using namespace std const int max 1001 int maxlen max max int maxlen string str1,string str2 return maxlen len1 len2 int main ...

編輯距離及編輯距離演算法

include include include using namespace std const int max 1001 int maxlen max max int maxlen string str1,string str2 return maxlen len1 len2 int main ...