求解兩個字串的最長公共子串行

2022-05-14 17:30:07 字數 4285 閱讀 2731

摘自:

摘自:一,問題描述

給定兩個字串,求解這兩個字串的最長公共子串行(longest common sequence)。比如字串1:bdcaba;字串2:abcbdab

則這兩個字串的最長公共子串行長度為4,最長公共子串行是:bcba

二,演算法求解

這是乙個動態規劃的題目。對於可用動態規劃求解的問題,一般有兩個特徵:①最優子結構;②重疊子問題

①最優子結構

設 x=(x1,x2,.....xn) 和 y= 是兩個序列,將 x 和 y 的最長公共子串行記為lcs(x,y)

找出lcs(x,y)就是乙個最優化問題。因為,我們需要找到x 和 y中最長的那個公共子串行。而要找x 和 y的lcs,首先考慮x的最後乙個元素和y的最後乙個元素。

1)如果 xn=ym,即x的最後乙個元素與y的最後乙個元素相同,這說明該元素一定位於公共子串行中。因此,現在只需要找:lcs(xn-1,ym-1)

lcs(xn-1,ym-1)就是原問題的乙個子問題。為什麼叫子問題?因為它的規模比原問題小。(小乙個元素也是小嘛....)

為什麼是最優的子問題?因為我們要找的是xn-1 和 ym-1 的最長公共子串行啊。。。最長的!!!換句話說,就是最優的那個。(這裡的最優就是最長的意思)

2)如果xn != ym,這下要麻煩一點,因為它產生了兩個子問題:lcs(xn-1,ym) 和 lcs(xn,ym-1)

因為序列x 和 序列y 的最後乙個元素不相等嘛,那說明最後乙個元素不可能是最長公共子串行中的元素嘛。(都不相等了,怎麼公共嘛)。

lcs(xn-1,ym)表示:最長公共序列可以在(x1,x2,....x(n-1)) 和 (y1,y2,...yn)中找。

lcs(xn,ym-1)表示:最長公共序列可以在(x1,x2,....xn) 和 (y1,y2,...y(n-1))中找。

求解上面兩個子問題,得到的公共子串行誰最長,那誰就是 lcs(x,y)。用數學表示就是:

lcs=max

由於條件 1)  和  2)  考慮到了所有可能的情況。因此,我們成功地把原問題 轉化 成了 三個規模更小的子問題。

②重疊子問題

重疊子問題是啥?就是說原問題 轉化 成子問題後,  子問題中有相同的問題。咦?我怎麼沒有發現上面的三個子問題中有相同的啊????

ok,來看看,原問題是:lcs(x,y)。子問題有 ❶lcs(xn-1,ym-1)    ❷lcs(xn-1,ym)    ❸lcs(xn,ym-1)

初一看,這三個子問題是不重疊的。可本質上它們是重疊的,因為它們只重疊了一大部分。舉例:

第二個子問題:lcs(xn-1,ym) 就包含了:問題❶lcs(xn-1,ym-1),為什麼?

因為,當xn-1 和 ym 的最後乙個元素不相同時,我們又需要將lcs(xn-1,ym)進行分解:分解成:lcs(xn-1,ym-1) 和 lcs(xn-2,ym)

也就是說:在子問題的繼續分解中,有些問題是重疊的。

由於像lcs這樣的問題,它具有重疊子問題的性質,因此:用遞迴來求解就太不划算了。因為採用遞迴,它重複地求解了子問題啊。而且注意哦,所有子問題加起來的個數 可是指數級的哦。。。。

這篇文章中就演示了乙個遞迴求解重疊子問題的示例。

那麼問題來了,你說用遞迴求解,有指數級個子問題,故時間複雜度是指數級。這指數級個子問題,難道用了動態規劃,就變成多項式時間了??

呵呵噠。。。。

關鍵是採用動態規劃時,並不需要去一 一 計算那些重疊了的子問題。或者說:用了動態規劃之後,有些子問題 是通過 「查表「 直接得到的,而不是重新又計算一遍得到的。廢話少說:舉個例子吧!比如求fib數列。關於fib數列,可參考:

求fib(5),分解成了兩個子問題:fib(4) 和 fib(3),求解fib(4) 和 fib(3)時,又分解了一系列的小問題....

從圖中可以看出:根的左右子樹:fib(4) 和 fib(3)下,是有很多重疊的!!!比如,對於 fib(2),它就一共出現了三次。如果用遞迴來求解,fib(2)就會被計算三次,而用dp(dynamic programming)動態規劃,則fib(2)只會計算一次,其他兩次則是通過」查表「直接求得。而且,更關鍵的是:查詢求得該問題的解之後,就不需要再繼續去分解該問題了。而對於遞迴,是不斷地將問題分解,直到分解為 基準問題(fib(1) 或者 fib(0))

說了這麼多,還是要寫下最長公共子串行的遞迴式才完整。借用網友的一張圖吧:)

c[i,j]表示:(x1,x2....xi) 和 (y1,y2...yj) 的最長公共子串行的長度。(是長度哦,就是乙個整數嘛)。公式的具體解釋可參考《演算法導論》動態規劃章節

這張dp表很是重要,從中我們可以窺見最長公共子串行的**,同時可以根據這張表列印出最長公共子串行的構成路徑

最長公共子串行列印路徑的模板遞迴法:

1 #include2 #include3 #include4

using

namespace

std; 5

const

int n = 1010;

6char

a[n],b[n]; 7

intdp[n][n]; 8

intflag[n][n]; 9

void print(int i,int

j)10

15if(!flag[i][j])

1620

else

if(flag[i][j]==1)21

24else

if(flag[i][j]=-1)25

28}29int

main()

3047

else

4854

else

5559}60

}61}62

print(lena,lenb);63}

64return0;

65 }

view code

非遞迴,在這裡因為是逆序的回溯,所以我使用了棧來儲存路徑

1 #include2 #include

3 #include4 #include5

using

namespace

std;

6#define n 1010

7int

dp[n][n];

8charc;9

intmain()

1026}27

int i=la,j=lb;

28 stacks;

29while

(dp[i][j])

3035

else

if(dp[i][j]==dp[i][j-1])///

來自於上方向

3639

else

if(dp[i][j]>dp[i-1][j-1])///

來自於左上方向

4045}46

while(!s.empty())

4752

return0;

53 }

求解兩個字串的最長公共子串行

一,問題描述 給定兩個字串,求解這兩個字串的最長公共子串行 最長公共序列 比如字串1 bdcaba 字串2 abcbdab 則這兩個字串的最長公共子串行長度為4,最長公共子串行是 bcba 二,演算法求解 這是乙個動態規劃的題目對於可用動態規劃求解的問題,一般有兩個特徵 最優子結構 重疊子問題 最優...

求解兩個字串的最長公共子串行

一,問題描述 給定兩個字串,求解這兩個字串的最長公共子串行 longest common sequence 比如字串1 bdcaba 字串2 abcbdab 則這兩個字串的最長公共子串行長度為4,最長公共子串行是 bcba 二,演算法求解 這是乙個動態規劃的題目。對於可用動態規劃求解的問題,一般有兩...

求解兩個字串的最長公共子串

求解兩個字串的最長公共子串 比如字串1 helloworld 字串2 hloop 則這兩個字串的最長公共子串行長度為2,最長公共子串行是 lo 問題定義 lcs i j 為以s1 i 與s2 j 為結尾的的最長公共子串的長度 遞推公式 lcs xn,ym lcs xn 1,ym 1 1 if x n...