首先要明確的是子串行的概念,注意啦,子串行不等於子串。子串行是乙個字串s去掉零個或者多個字元後所剩下的字串就叫做子串行。
最長公共子串行的意思就是尋找兩個給定字串的的子串行,該子串行在兩個字串中以相同的次序出現,但是不一定是連續的。(連續的那是子串)
例如序列x=abcbdab,y=bdcaba。序列bca是x和y的乙個公共子串行,但是不是x和y的最長公共子串行,子串行bcba是x和y的乙個lcs,序列bdab也是。
最簡單想到的
尋找lcs的一種方法是列舉x所有的子串行,然後逐一檢查是否是y的子串行,並隨時記錄發現的最長子序列。假設x有m個元素,則x有2^m個子序列,指數級的時間,對長序列不實際。
其實最長公共子串行是動態規劃(dp)的典型例子。
設x=1,x2,…,xm>和y=1,y2,…,yn>為兩個字串,lcs(x,y)表示x和y的乙個最長公共子串行,可以看出
如果xm=yn,則lcs ( x,y ) =xm
+ lcs( xm-1,yn-1
)。如果xm!=yn,則lcs( x,y )= max
lcs問題也具有重疊子問題性質:為找出x和y的乙個lcs,可能需要找x和yn-1的乙個lcs以及xm-1和y的乙個lcs。但這兩個子問題都包含著找xm-1和yn-1的乙個lcs,等等.
dp最終處理的還是數值(極值做最優解),找到了最優值,就找到了最優方案;為了找到最長的lcs,我們定義dp[i][j]記錄序列lcs的長度,合法狀態的初始值為當序列x的長度為0或y的長度為0,公共子串行lcs長度為0,即dp[i][j]=0,所以用i和j分別表示序列x的長度和序列y的長度,狀態轉移方程為
dp[i][j] = 0 如果i=0或j=0
dp[i][j] = dp[i-1][j-1] + 1 如果x[i-1] = y[i-1] (x[i-1]就是x陣列中的第i個)
dp[i][j] = max 如果x[i-1] != y[i-1]
#include using namespace std;
/* lcs
* 設序列長度都不超過20*/
int dp[21][21]; /* 儲存lcs長度, 下標i,j表示序列x,y長度 */
char x[21];
char y[21];
int i, j;
void main()
else if(dp[i][j-1] > dp[i-1][j])
else}}
printf("len of lcs is: %d\n", dp[xlen][ylen]);
/* 輸出lcs 本來是逆序列印的,可以寫一遞迴函式完成正序列印
這裡採用的方法是將y作為臨時儲存lcs的陣列,最後輸出y
*/i = xlen;
j = ylen;
int k = dp[i][j];
char lcs[21] = ;
while(i && j)
else if(x[i-1] != y[j-1] && dp[i-1][j] > dp[i][j-1])
else
}printf("%s\n",lcs);
}
例題:uva 111
**:
LCS 最長公共子串行
問題描述 我們稱序列z z1,z2,zk 是序列x x1,x2,xm 的子串行當且僅當存在嚴格上 公升的序列 i1,i2,ik 使得對 j 1,2,k,有 xij zj。比如z a,b,f,c 是 x a,b,c,f,b,c 的子串行。現在給出兩個序列 x和 y,你的任務是找到 x和 y的最大公共子...
LCS最長公共子串行
求兩個字串的最大公共子串行問題 子串行的定義 若給定序列x 則另一串行z 是x的子串行是指存在乙個嚴格遞增下標序列使得對於所有j 1,2,k有 zj xij。例如,序列z 是序列x 的子序列,相應的遞增下標序列為。分析 用動態規劃做 1.最長公共子串行的結構 事實上,最長公共子串行問題具有最優子結構...
LCS最長公共子串行
lcs是longest common subsequence的縮寫,即最長公共子串行。乙個序列,如果是兩個或多個已知序列的子串行,且是所有子串行中最長的,則為最長公共子串行。複雜度對於一般的lcs問題,都屬於np問題。當數列的量為一定的時,都可以採用動態規劃去解決。解法動態規劃的乙個計算最長公共子串...