(字符串)最长公共子序列(Longest-Common-Subsequence,LCS)
問(wèn)題:
最長(zhǎng)公共子序列就是尋找兩個(gè)給定序列的子序列,該子序列在兩個(gè)序列中以相同的順序出現(xiàn),但是不必要是連續(xù)的。
例如序列X=ABCBDAB,Y=BDCABA。序列BCA是X和Y的一個(gè)公共子序列,但是不是X和Y的最長(zhǎng)公共子序列,子序列BCBA是X和Y的一個(gè)LCS,序列BDAB也是。
思路:
1、最簡(jiǎn)單的方法就是暴力枚舉。
先列舉X所有的子序列,然后檢查是否為Y的子序列,并記錄最長(zhǎng)的子序列。當(dāng)該方法復(fù)雜度太高,假設(shè)X的長(zhǎng)度為m,則X的子序列個(gè)數(shù)為2^m,指數(shù)級(jí)的復(fù)雜度是不實(shí)際的。
2、動(dòng)態(tài)規(guī)劃思想。
設(shè)X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>為兩個(gè)序列,LCS(Xm,Yn)表示以Xm結(jié)尾的字符串和以Yn結(jié)尾的字符串的一個(gè)最長(zhǎng)公共子序列,可以看出
如果xm=yn,則LCS ( Xm,Yn?) = xm?+ LCS ( Xm-1,Yn-1?)。
如果xm!=yn,則LCS( Xm,Yn )= max{ LCS ( Xm-1, Yn ), LCS ( Xm, Yn-1?) }
最長(zhǎng)公共子序列長(zhǎng)度:
狀態(tài)轉(zhuǎn)移方程:
初始狀態(tài):dp[i][j]=0 if i==0 || j==0
轉(zhuǎn)移方程:dp[i][j] = dp[i-1][j-1] + 1 ?if (X[i-1]==Y[j-1])
dp[i][j] = max ( dp[i-1][j], dp[i][j-1] ) ?if (X[i-1]!=Y[j-1])
最長(zhǎng)公共子序列:
通過(guò)狀態(tài)轉(zhuǎn)移方程,可以逆推出最長(zhǎng)子序列,如果x[i-1]==y[j-1] && dp[i][j]==dp[i-1][j-1]+1,則x[i-1]為最長(zhǎng)子序列的元素,否則如果x[i-1]==y[j-1] && dp[i-1][j]>dp[i][j-1],則i--,否則j--,這樣就得到一個(gè)倒序的最長(zhǎng)子序列,具體見(jiàn)參考代碼。
復(fù)雜度分析:
上述思路的時(shí)間復(fù)雜度為O(m*n),空間復(fù)雜度也為O(m*n);
dp[i][j] = dp[i-1][j-1] + 1 ?if (X[i-1]==Y[j-1])
dp[i][j] = max ( dp[i-1][j], dp[i][j-1] ) ?if (X[i-1]!=Y[j-1])
從狀態(tài)轉(zhuǎn)移方程可以看到,如果只求最長(zhǎng)公共子序列長(zhǎng)度的話,每一次轉(zhuǎn)移的時(shí)候只與前一狀態(tài)有關(guān),因此空間復(fù)雜度可以從m*n降為2*n,只保存當(dāng)前和前一狀態(tài),時(shí)間復(fù)雜度不變。
代碼:
#include <iostream> #include <vector>using namespace std;int LCS(char *str1,int len1,char *str2,int len2){// calculate length of LCSvector<vector<int> > dp(len1+1,vector<int>(len2+1,0));for(int i=0;i<=len1;i++){for(int j=0;j<=len2;j++){if(i==0 || j==0)dp[i][j]=0;else{if(str1[i-1]==str2[j-1])dp[i][j]=dp[i-1][j-1]+1;elsedp[i][j]=max(dp[i-1][j],dp[i][j-1]);}}}// record the LCSint len=dp[len1][len2];char lcsArr[len];lcsArr[len]='\0';int i=len1,j=len2;while(i && j){if(str1[i-1]==str2[j-1] && dp[i][j]==dp[i-1][j-1]+1){lcsArr[--len]=str1[i-1];i--;j--;}else if(str1[i-1]!=str2[j-1] && dp[i-1][j]>dp[i][j-1])i--;elsej--;}cout<<"Length of LCS is: "<<len<<endl;cout<<"SubSequency of LCS is: "<<lcsArr<<endl;return dp[len1][len2]; }int main() {char str1[]="abcd";char str2[]="bd";int len1=sizeof(str1)/sizeof(str1[0])-1;int len2=sizeof(str2)/sizeof(str2[0])-1;cout << LCS(str1,len1,str2,len2) << endl;return 0; } int LCS2(char *str1,int len1,char *str2,int len2){// only to calculate length of LCS// reduce the space complexity from m*n to 2*nvector<vector<int> > dp(2,vector<int>(len2+1,0));int k;for(int i=0;i<=len1;i++){k=i&1;for(int j=0;j<=len2;j++){if(j==0)dp[k][j]=0;else{if(str1[i-1]==str2[j-1])dp[k][j]=dp[1-k][j-1]+1;elsedp[k][j]=max(dp[1-k][j],dp[k][j-1]);}}}cout<<"Length of LCS is: "<<dp[k][len2]<<endl;return dp[k][len2]; }運(yùn)行結(jié)果:
?
轉(zhuǎn)載于:https://www.cnblogs.com/AndyJee/p/4469196.html
總結(jié)
以上是生活随笔為你收集整理的(字符串)最长公共子序列(Longest-Common-Subsequence,LCS)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 数字键盘打不出来数字是怎么回事
- 下一篇: LaTeX中用BibTex管理参考文献