最長公共子串行 動態規劃求解

2022-05-19 13:40:53 字數 3503 閱讀 9255

問題:例如:x=,y=,那麼,二者的最長公共子串行是,長度為4。

我們首先需要搞清楚以下兩個概念:

最長公共子串行 vs 最長公共子串:

找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。

上述問題中的最長公共子串行與最長公共子串是一樣的。

但是再舉例x=,y=,二者的最長公共子串行是,而二者的最長公共子串是。

求解思路:

1.分析最優解的結構特徵:

設zk=是xm=和yn=的最長公共子串行。

則可以得到:

若xm=yn=zk,那麼zk-1=是xm-1=和yn-1=的最長公共子串行;

若xm≠yn,xm≠zk,則去除xm後,zk=仍然是xm-1=和yn=的最長公共子串行;

若xm≠yn,yn≠zk,則去除yn後,zk=仍然是xm=和yn-1=的最長公共子串行;

2.建立最優值的遞迴式

資料結構選擇:

用c[i][j]表示xi和yj的最長公共子串行長度(這一步很關鍵,越到右下角,值會越來越大,我們最後只需要選取右下角的值就可以確定最長公共子串行的長度)

討論:若xi=yj=zk,那麼c[i][j] = c[i-1][j-1] + 1;

若xi≠yj,xi≠zk,那麼xi需要進一步縮小乙個長度進行匹配,即去除xi不影響整體的最長子序列變化,c[i][j] = c[i-1][j] ;

若xi≠yj,yj≠zk,那麼yj需要進一步縮小乙個長度進行匹配,即去除yj不影響整體的最長子序列變化,c[i][j] = c[i][j-1] ;

結束條件,若i=0或者j=0,則c[i][j]=0。

所以,在xi≠yj的情況下,有兩種情況,c[i][j]必等於兩種情況下的最大值,即c[i][j] = max(c[i-1][j], c[i][j-1])

3.自底向上計算最優值,並記錄最優值與最優策略

我們由上面可以知道,c[0][j]=0或者c[i][0]=0.

先使i = 1,則求x1與逐一比較。如圖,x1≠y1,執行c[1][1] = max(c[0][1], c[1][0])  =0,接著,x1=y2,則執行,c[1][2] = c[0][1] + 1=1 ,接著,x1≠y3,則執行c[1][3] = max(c[0][3], c[1][2])  =1

,......這樣就求出了x1與yn的最長公共子串行長度;

然後,i = 2,則建立在x1比較的基礎上就可以求出與的最長公共子串行長度;

然後,i = 3,建立在的基礎上,則可以求出與的最長公共子串行長度;

......

然後,i = m,建立在的基礎上,則可以求出與的最長公共子串行長度;

4.構造最優解

在知道了最長公共子串行的長度之後,我們還需要知道最長公共子串行中都是哪些元素。我們在c[i][j]陣列的右下角能夠得到最長公共子串行的長度,那麼,我們可以反向推出這個元素分別是什麼。

由上述,我們可以得到:

若xi=yj=zk,c[i][j] = c[i-1][j-1] + 1;

若xi≠yj,xi≠zk,c[i][j] = c[i-1][j] ;

若xi≠yj,yj≠zk,c[i][j] = c[i][j-1] ;

所以,c[i][j]由上述三個等式中的乙個得到,那麼我們只需要記錄下c[i][j]是從三個等式中哪乙個得到的,那麼對應的元素我們就知道了。

這樣,我們就必須在借助乙個陣列就行儲存了,我們建立新的陣列b[i][j]來記錄是從哪個等式中得到,即構造出下列結構。

若xi=yj=zk,c[i][j] = c[i-1][j-1] + 1,則b[i][j] = 1,那麼我們就可以取出xi或者yj作為最長公共子串行中的元素;

若xi≠yj,yj≠zk,c[i][j] = c[i][j-1],則b[i][j] = 2,那麼我們就可以去追蹤c[i][j-1];

若xi≠yj,xi≠zk,c[i][j] = c[i-1][j] ,則b[i][j] = 3,那麼我們就可以去追蹤c[i-1][j];

追蹤到i=0或者j=0,停止,如下圖則是根據c[i][j]取值的**將b[i][j]陣列補充完整

下圖為兩個序列的最終比較情況:我們由上述構造b[i][j]的方法得知,若 b[i][j]= 2,那麼我們去追蹤c[i][j-1],若b[i][j]= 3,那麼我們去追蹤c[i-1][j],換言之,就是b[i][j]= 2

,就往左找,b[i][j]= 3,就往右找,若b[i][j]= 1,就可以輸出此時的xi或者yj

上述的思路理解清楚了,我們就可以上**了,**如下:

1 #include 2 #include 3

using

namespace

std;

4const

int n=1024;5

intc[n][n],b[n][n];

6char

s1[n],s2[n];

7int

len1,len2;

8void

lcs()916

else

21else25}

26}27}

28}2930

void lcs_print(int i, int

j)31

35if(b[i][j] == 1)39

else

if(b[i][j] == 2)42

else45}

4647

intmain()

4858

for(int j = 0; j <= len2; j++)

61lcs();

62 cout << "

s1與s2的最長公共子串行的長度是:

"<< c[len1][len2] <

63 cout << "

s1與s2的最長公共子串行是:";

64lcs_print(len1,len2);

65return0;

66 }

ACM 最長公共子串行 動態規劃求解

最長公共子串行問題 給你兩個字串a m b n 求出他們的公共子字串的長度 子字串不需要再原字串中連續 這個問題的一般想法是 1.找出a m 中的每個子字串 2.看其是否也能存在在b n 中 3.找出公共子字串中最大的乙個。然而這個方法對於計算機來說實在是過於複雜,比較好的方法是使用動態規劃的方法 ...

最長公共子串行 動態規劃

經常會遇到複雜問題不能簡單地分解成幾個子問題,而會分解出一系列的子問題。簡單地採用把大問題分解成子問題,並綜合子問題的解匯出大問題的解的方法,問題求解耗時會按問題規模呈冪級數增加。為了節約重複求相同子問題的時間,引入乙個陣列,不管它們是否對最終解有用,把所有子問題的解存於該陣列中,這就是動態規劃法所...

最長公共子串行 動態規劃

關於用動態規劃法求兩個序列的最長公共子串行問題的相關知識見 王曉東 計算機演算法設計與分析 第三章。注意,這裡所指的最長公共子串行是可以不相鄰的,與平常所說的最長公共子串 相鄰的 不一樣。直接上 lcs.h ifndef lcs h define lcs h class lcstring endif...