1. 程式人生 > >最長公共子序列與編輯距離動態規劃原理分析

最長公共子序列與編輯距離動態規劃原理分析

前段時間看過最長公共子序列的動態規劃演算法,這兩天又看到了編輯距離的動態規劃演算法,感覺兩者有很相似的地方,而狀態轉移方程又不十分直觀,所以打算把其原理記錄下來,以防以後忘記。

先看最長公共子序列,記兩個序列分別為a[m],b[n].其狀態轉移方程如下:

從中我們可以看出分成兩種情況,第一種是a[i]=b[j],第二種是a[i]!=b[j]

1.a[i]=b[j]。這種情況還是比較顯然的,既然a[i]=b[j]了,我們就可以將a[0-i],b[0-j]如下排列:

a[0]a[1] .....a[i-1] a[i]

       b[0]  ....b[j-1]b[j]

這時候我們就把a[i],b[j]從上面這兩個個序列中去掉,然後就變成了a[0-(i-1)],b[0-(j-1)]這種情況了,而這種情況我們已經知道c[i-1][j-1]了,所以c[i][j]就比c[i-1][j-1]多了一項a[i]與b[j]匹配的情況,所以c[i][j]=c[i-1][j-1]+1。

當然有人可能就奇怪了,為啥能一定保證a[i]b[j]匹配時的情況一定是公共子序列最大的情況,如果a[i]與b[j]不匹配說不定c[i][j]更大呢。那我們就看一下這種情況:

假設在某種匹配方式下,a[i]與b[j]不匹配。這時a[i]與b[0-(j-1)]的某個數匹配,或b[j]與a[0-(i-1)]中的某個數匹配(如果這兩種情況都不發生,說明a[i]、b[j]都不在最長公共子序列k中,這時如果把a[i]與b[j]匹配的這一組加入k中得到K,顯然K>k,這說明k不是最長公共子序列,產生了矛盾)。不妨設發生了a[i]與b[0-(j-1)]的某個數匹配的情況,如下

a[0]a[1] .....a[i-1] a[i]  

       b[0]  ....b[j-k-1]b[j-k]  b[j-k+1] .....b[j]

這時候,a[i-1]就只能與b[j-k]之前的數匹配了。那麼,在這種匹配方式下的c`[i][j]=c[i-1][j-k-1]+1。而根據狀態轉移方程,c[i-1][j-1]>=c[i-1][j-k-1](使用數學歸納法),所以,a[i]b[j]匹配的c[i][j]>=c`[i][j].這說明,我們假設中的a[i]與b[j]不匹配的匹配方式不會是唯一最優的方式,而a[i]b[j]匹配的匹配方式則是一種最優的匹配方式。

2.a[i]!=b[j]。

這時候a[i]b[j]就不可能再匹配上了。然而在求a[0-i]b[0-j]的最長公共子序列時,我們還可以人為地分為3種情況:

1、a[i]不在最長公共子序列中

2. b[j]不在最長公共子序列中

3.a[i]和b[j]都不在最長公共子序列中.

先看情況1、2。12這兩種情況本質上是一種,所以不妨設是第二種情況,這時候最長公共子序列中就沒有b[j]什麼事了,顯然a[0-i]b[0-j]的最長公共子序列與a[0-i]b[0-(j-1)]的最長公共子序列是完全一樣的。所以 c[i][j]=c[i][j-1]

再看情況3.如果在a[0-i]b[0-j]最長公共子序列中b[j]不存在,說明b[j]對於其最長公共子序列沒有任何影響,那麼c[i][j]=c[i][j-1]。同理,c[i][j]=c[i-1][j]

這樣這三種情況都討論完了,但是在真正執行的時候我們可不知道到底是哪種情況最好。那就把三種情況都算出來,取三種情況中最大的,即c[i][j]=max(c[i-1][j],c[i][j-1])

那麼情況1、2綜合起來,加上i、j=0的情況,就得到了上圖中的狀態轉移方程.

然後再來看編輯距離問題。這一問題因為涉及到能對其中一個字串進行增添、刪除、替換操作,情況變得更為複雜。但思路上都是分情況討論,然後分別證明在每種情況下公式都是對的。

其狀態轉移方程如下

  • 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 i ≥ 1  且 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。
假設我們需要操作a[m]使其變換到b[n] 1、2、3情況都比較顯然,就不再證明,下面來看第四種情況:

第四種情況說明對a[0-i]的最少操作次數都是在對a[0-(i-1)]操作的基礎上進行的:edit(i-1, j) + 1相當於a[0-i]先刪去a[i]變成a[i-1]後再與b[0-j]匹配,edit(i, j-1) + 1相當於a[0-i]添加了一個a[i+1]=b[j]後再將a[0-i]與b[0-(j-1)]匹配(a新增b[j]等效於b刪去b[j]),edit(i-1, j-1) + f(i, j)相當於使a[i]替換為b[j]後,繼續進行a[i-1]到p[j-1]的操作。

同樣的問題,為什麼這樣做操作次數就會最少呢?

a[i]=b[j]的情況比較顯然,分析過程同下面,略過。

a[i]!=b[j]時,假設存在某種操作方式m,使得edit(m)=edit(i,j)<min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }

那麼我們來看一下在操作m後 變換為b[j]的a[p]的來源。

        1、若a[p]來自於向a中插入了一個新數aa,那麼我們採取操作m來變換a[0-i],但去掉新增aa的過程,那麼最終的效果就是a[0-i]變為b[0-(j-1)]。這時候這種操作的操作次數edit`(i,j-1)=edit(m)-1<edit(i,j-1),這樣就產生矛盾了(因為按照前提,不可能存在操作次數比edit(i,j-1)還少的從a[0-i]變化到b[0-(j-1)]的過程),說明若a`[j]來自於向a中插入了一個新數aa,不可能存在這種操作m

2、若a[p]來自於a[k](k<i,a[k]=b[j])(a[k]也可能是由替換產生的),即:將a[k]以後的數都刪去。那麼,顯然對a[0-(i-1)]執行操作m,但去掉"刪除a[i]"這一操作,最終的結果就是a[0-(i-1)]變為b[0-j]。這時候edit`(i-1,j)=edit(m)-1<edit(i,j-1),矛盾。

3。、若a[p]來自於a[i]替換為b[j],那麼,顯然對a[0-(i-1)]執行操作m,但去掉"替換a[i]"這一操作,最終的結果就是a[0-(i-1)]變為b[0-(j-1)]。這時候edit`(i-1,j)=edit(m)-1<edit(i-1,j-1),矛盾。

綜上123所述,不可能存在比min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }更少的操作次數,否則就會產生矛盾。同時,根據紅色部分的分析,我們知道,通過min{ edit(i-1, j) + 1, edit(i, j-1) + 1, edit(i-1, j-1) + f(i, j) }這一公式計算出的最小編輯次數是有方法來實際進行執行的。

上面就是最長公共子序列和編輯距離的動態規劃方程的原理分析,比較繁瑣,感覺發明演算法的人思路應該不是這樣,但對理解方程應該也有一些幫助。同樣問題的還有最長公共子串問題,個人感覺還是比較容易理解,就不再具體分析。

相關推薦

公共序列編輯距離動態規劃原理分析

前段時間看過最長公共子序列的動態規劃演算法,這兩天又看到了編輯距離的動態規劃演算法,感覺兩者有很相似的地方,而狀態轉移方程又不十分直觀,所以打算把其原理記錄下來,以防以後忘記。 先看最長公共子序列,記兩個序列分別為a[m],b[n].其狀態轉移方程如下: 從中我們可以看出

動態規劃——公共序列 公共

1、最長公共子序列LCS 問題,即最長公共子序列問題。它並不要求所求得的字元在所給定的字串中是連續的。比如輸入的兩個字串是 ABCBDAB 和 BDCABA,那麼,BCBA 和 BDAB 都是他們最長的公共子序列。則輸出它們的長度 4。假設兩個字串 A = [A0,A1...

動態規劃公共序列公共

1. 問題描述 子串應該比較好理解,至於什麼是子序列,這裡給出一個例子:有兩個母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs與belong中都出現過並且出現順序與母串保持一致,我們將其稱為公共子序列。最長公共子序列(Longest Common Subsequence

Java實現演算法導論中公共序列(LCS)動態規劃法

1、問題: 求兩字元序列的最長公共字元子序列LCS 2、求解:動態規劃法                      動態規劃的思路就是用一個矩陣來記錄兩個字串中所有位置的兩個字元之間的匹配情況,若是匹配則為1,否則為0。然後求出對角線最長的1序列,其對應的位置就是最長匹配子

HDU 1069 Monkey and Banana 上升序列進階(動態規劃

HDU 1069(動態規劃) Monkey and Banana Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description A group

公共串LCS問題(動態規劃及備忘錄方法)

動態規劃與備忘錄的LCS實現 動態規劃從下到上積累能量,中間值全部記錄以方便後期計算時呼叫,但有些時候很多記錄的值用不到,這個時候備忘錄方法則更好,可以減少記錄的值,其特點是自上到下,記錄少部分值。以LCS最長公共子串問題威力,分別給出兩種實現。 動態規劃法: pa

編輯距離公共序列總結

前言: 其實編輯距離和最長公共子序列是對同一個問題的描述,都能夠顯示出兩個字串之間的“相似度”,即它們的雷同程度。而子序列與字串的區別在於字串是連續的,子序列可以不連續,只要下標以此遞增就行。 編輯距離: Problem description:   設A 和B 是2 個

51nod 1183 編輯距離【線性dp+類似公共序列

ima else ems 俄羅斯 hid ace mem std 類型 1183 編輯距離 基準時間限制:1 秒 空間限制:131072 KB 分值: 0 難度:基礎題 收藏 關註 編輯距離,又稱Levenshtein距離

大子序列遞增序列公共串、公共序列、字串編輯距離總結

一、最大子序列 即找出由陣列成的一維陣列中和最大的連續子序列。例如{5, -6, 4, 2}的最大子序列是{4, 2},它們的和是6。 思路:假設陣列為num,用dp[i]儲存當遍歷到num[i]時,num[0]~num[i]之間求得的最大子序列的和。 遍歷num,當遍歷到nu

] 找工作知識儲備(2)---陣列字串那些經典演算法:大子序列和,遞增序列公共串,公共序列,字串編輯距離不重複串,迴文

作者:寒小陽 時間:2013年9月。 0、前言         這一部分的內容原本是打算在之後的字串或者陣列專題裡面寫的,但看著目前火熱進行的各家網際網路公司筆試面試中,出現了其中的一兩個內容,就隨即將這些經典問題整理整理,單寫一

公共序列-LCS問題 (LCSLIS在特殊條件下的轉換) [洛谷1439]

一個 har define 分享 amp lis read ios stack 題目描述 給出1-n的兩個排列P1和P2,求它們的最長公共子序列。 輸入 第一行是一個數n, 接下來兩行,每行為n個數,為自然數1-n的一個排列。 輸出 一個數,即最長公

公共公共序列

兩個 ring 數組存儲 src str int sdf range div 一、最長公共子串(Longest Common Substring) 遍歷的時候用一個二維數組存儲相應位置的信息,如果兩個子串1與子串2相應位置相等:則看各自前一個位置是否相等,相等則該位置值B[

哈爾濱理工大學軟體微電子學院第八屆程式設計競賽同步賽(高年級) E 小樂樂匹配字串 【公共序列

傳送門:https://ac.nowcoder.com/acm/contest/301/E   求最長公共子序列。 立個 flag 搞dp。   AC code: #include <cstdio> #include <iostream> #inc

公共公共序列(動歸實現)

什麼是子序列?一個給定的序列的子序列,就是將給定序列中零個或多個元素去掉之後得到的結果。 什麼是子串?給定串中任意個連續的字元組成的子序列稱為該串的子串。(相對於子序列,子串是連續的) 如abcde

常考的經典演算法--公共序列(LCS)公共串(DP)

https://blog.csdn.net/qq_31881469/article/details/77892324 《1》最長公共子序列(LCS)與最長公共子串(DP) http://blog.csdn.net/u012102306/article/details/53184446 h

演算法設計分析學習筆記——公共序列

最長公共子問題待解決問題:    給定兩個序列X和Y,求其一個最長公共的序列Z。    補充解釋:X(m)={x1, x2,,,,,xm},Y(n)={y1, y2,,,,,yn},X和Y可以有共同的元素,Z是這些共同元素的集合,其元素順序在XYZ中都是升序排序的(Z中元素的

【資料結構演算法】公共公共序列

1.最長公共子串:找出s和t的公共子字串的最大長度。 使用dp,定義子問題dp[i][j]:公共子串結束在位置i,j的長度。如果s[i] != t[j],那麼很顯然是0,否則dp[i][j] = dp[i - 1][j - 1] + 1。 程式碼: public int

演算法7.自然合併排序公共序列

如果陣列中部分元素已按自然數順序排放,例如,陣列 ,則初期自然排好序的子陣列段顯然有4段,分別為 , , 和 。請充分利用上述特點設計並實現一個自然合併排序演算法。 (1) 演算法設計思路 先對陣列進行一次線性掃描,

公共序列-動態規劃(Python)

最長公共子串(The Longest Common Substring)        LCS問題就是求兩個字串最長公共子串的問題。解法就是用一個矩陣來記錄兩個字串中所有位置的兩個字元之間的匹配情況,若是匹配則為左上方的值加1,否則為0。然後求出對角線最長的1的序列,其對應

011-公共序列-動態規劃-《演算法設計技巧分析》M.H.A學習筆記

給出兩個長度分別為n和m的字串A和B,確定A和B中最長公共子序列的長度。 樸素演算法:列舉A中所有的子序列2n個,並逐個判斷其是否在B中(Θ(m)耗費)。時間複雜度為Θ(m2n)。 利用動態規劃可