Edit Distance編輯距離與動態規劃

2021-09-28 20:29:01 字數 4062 閱讀 4851

編輯距離是指將乙個字串轉化為另外乙個字串,需要的最少的編輯操作次數,這些操作包括增加、刪除或者替換某個字元。可以看出,編輯距離越大,說明兩個字串的相似度越小;相反,編輯距離越小,說明這兩個字串的相似程度越大。兩個字串的編輯距離為0則說明這兩個字串相同。

編輯距離的計算方式比較多,比較著名的有萊文斯坦距離(levenshten distance)和最長公共子串長度(longest common substring length)。

比如:字串mitcmu和mtacnu的萊文斯坦距離是3,最長公共子串長度是4.

萊文斯坦距離就是找出兩個字串之間的差異度,即最小的編輯次數。

這個問題其實可以使用回溯來解決,看你能否想到,思路如下:

依次考察乙個字串中的每個字元,跟另乙個字串中的字元是否匹配,比如a[i]和b[j]如果匹配,則繼續考察a[i+1]和b[j+1].但如果a[i]和b[j]不匹配呢?如果不匹配,則有以下幾種方式來處理:

其實回溯計算的過程如果沒有重複子問題則直接就用回溯就可以了,但是如果有較多的重複子問題動態規劃則是更高效的方式。

dp思想解決問題的關鍵其實找到狀態轉移方式,而萊文斯坦距離的dp狀態轉移方式其實有三種,比如對於長度分別是n和m的字元陣列a和b來說:

如果:a[i]!=b[j],那麼:min_edist(i, j) 就等於:

min(min_edist(i-1,j)+1, min_edist(i,j-1)+1, min_edist(i-1,j-1)+1)

如果:a[i]==b[j],那麼:min_edist(i, j) 就等於:

min(min_edist(i-1,j)+1, min_edist(i,j-1)+1,min_edist(i-1,j-1))

其中,min_edit(i,j)表示考察到a[i]和b[j]時經過的最小的編輯距離;min 表示求三數中的最小值。

試著理解下:

無論是min_edist(i-1,j)還是min_edist(i,j-1),下乙個狀態如果是min_edist(i,j)必定是其中乙個且僅是乙個字串往後移動了乙個下標到達的min_edist(i,j)。這說明發生了編輯,編輯距離加一了。

當a[i]!=b[j]時, min_edist(i-1,j-1)需要加1容易理解因為a[i]和b[j]不等需要編輯。

當a[i]==b[j]時,min_edist(i-1,j-1)不需要加1,因為字元a[i]和b[j]相等不需要編輯。

這裡有點難理解

min_edist(i,j-1)或者min_edist(i-1,j)轉移到min_edist(i,j)應該加1,因為min_edist(i,j-1)或者min_edist(i-1,j)表示的是編輯距離,而編輯距離表示的是達到次數x時兩個字串相等。既然相等就肯定同時往後移動下標,所以不能簡單理解為編輯距離,而應該思考min_edist(i-1,j)和min_edist(i,j)之間的狀態轉移關係。

mindist[i-1][j]或mindist[i][j-1]到mindist[i][j]的轉移,就是在字串中增加了乙個字元

比如hello和hllo,當i指向e,j指向l的時候,往hllo中加入字元e成為hello,那麼此時j-1就是e,

j是l,就相當於是mindist[i][j-1]到mindist[i][j]的轉移.

於是he和hel的編輯距離mindist[i][j]為mindist[i][j-1]+1

思路:如果 a[i] 與 b[j] 互相匹配,我們將最大公共子串長長度加一,並且繼續考察 a[i+1] 和 b[j+1]

如果 a[i] 與 b[j] 不匹配,最長公共子串長度不變,此時如下兩種處理方式:

狀態轉移公式:

如果:a[i]==b[j],那麼:max_lcs(i, j) 就等於: max(max_lcs(i-1,j-1)+1, max_lcs(i-1, j), max_lcs(i, j-1));

如果:a[i]!=b[j],那麼:max_lcs(i, j) 就等於: max(max_lcs(i-1,j-1), max_lcs(i-1, j), max_lcs(i, j-1));

其中 max 表示求三數中的最大值。

package com.study.algorithm.dp;

/** * @auther: jeffsheng

* @date: 2019/10/21 16:02

* @description: 編輯距離的實現

* */

public

class

editdistance

if(j < m)

if(edist < mindist)

return;}

// 兩個字元匹配

if(a[i]

== b[j]

)else

}/**

* 動態規劃思想解決編輯距離問題

* 即由前乙個狀態決定後乙個狀態

* @param a 字元陣列a

* @param n a的長度n

* @param b 字元陣列b

* @param m b的長度m

* @return

*/public

intlwstdp

(char

a,int n,

char

b,int m)

else

if(j !=0)

else

}// 初始化第 0 列:a[0..i] 與 b[0..0] 的編輯距離

for(

int i =

0; i < n;

++i)

else

if(i !=0)

else

}// 按行填表

for(

int i =

1; i < n;

++i)

else}}

return mindist[n-1]

[m-1];

}private

intmin

(int x,

int y,

int z)

if(y < minv)

if(z < minv)

return minv;

}/**

* 動態規劃思想+最長公共子串長度法來計算編輯距離

* @param a

* @param n

* @param b

* @param m

* @return

*/public

intlcs

(char

a,int n,

char

b,int m)

else

if(j !=0)

else

}// 初始化第 0 列:a[0..i] 與 b[0..0] 的 maxlcs

for(

int i =

0; i < n;

++i)

else

if(i !=0)

else

}// 填表

for(

int i =

1; i < n;

++i)

else}}

return maxlcs[n-1]

[m-1];

}private

intmax

(int x,

int y,

int z)

if(y > maxv)

if(z > maxv)

return maxv;

}public

static

void

main

(string[

] args)

}

Edit Distance 編輯距離

編輯距離是一道經典的動態規劃 dynamic programing 問題。下面將詳細地介紹解法。我們先定義一下cache i j 表示,要將word1 0.i 1 轉化成word2 0.j 1 的最小步驟。比如,我們的word1 aeee world2 adef a def aeee 我們先來考慮一...

編輯距離 Edit distance

插入乙個字元,例如 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 ...

編輯距離(Edit Distance)

edit distance 1000 ms 65535 kb 568 2526 設a 和b 是2 個字串。要用最少的字元操作將字串a 轉換為字串b。這裡所說的字元操作包括 1 刪除乙個字元 2 插入乙個字元 3 將乙個字元改為另乙個字元。將字串a變換為字串b 所用的最少字元運算元稱為字串a到b 的編...