(字符串)最长公共子序列(Longest-Common-Subsequence,LCS)
問題:
最長公共子序列就是尋找兩個給定序列的子序列,該子序列在兩個序列中以相同的順序出現,但是不必要是連續的。
例如序列X=ABCBDAB,Y=BDCABA。序列BCA是X和Y的一個公共子序列,但是不是X和Y的最長公共子序列,子序列BCBA是X和Y的一個LCS,序列BDAB也是。
思路:
1、最簡單的方法就是暴力枚舉。
先列舉X所有的子序列,然后檢查是否為Y的子序列,并記錄最長的子序列。當該方法復雜度太高,假設X的長度為m,則X的子序列個數為2^m,指數級的復雜度是不實際的。
2、動態規劃思想。
設X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>為兩個序列,LCS(Xm,Yn)表示以Xm結尾的字符串和以Yn結尾的字符串的一個最長公共子序列,可以看出
如果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?) }
最長公共子序列長度:
狀態轉移方程:
初始狀態:dp[i][j]=0 if i==0 || j==0
轉移方程: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])
最長公共子序列:
通過狀態轉移方程,可以逆推出最長子序列,如果x[i-1]==y[j-1] && dp[i][j]==dp[i-1][j-1]+1,則x[i-1]為最長子序列的元素,否則如果x[i-1]==y[j-1] && dp[i-1][j]>dp[i][j-1],則i--,否則j--,這樣就得到一個倒序的最長子序列,具體見參考代碼。
復雜度分析:
上述思路的時間復雜度為O(m*n),空間復雜度也為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])
從狀態轉移方程可以看到,如果只求最長公共子序列長度的話,每一次轉移的時候只與前一狀態有關,因此空間復雜度可以從m*n降為2*n,只保存當前和前一狀態,時間復雜度不變。
代碼:
#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]; }運行結果:
?
轉載于:https://www.cnblogs.com/AndyJee/p/4469196.html
總結
以上是生活随笔為你收集整理的(字符串)最长公共子序列(Longest-Common-Subsequence,LCS)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数字键盘打不出来数字是怎么回事
- 下一篇: 小米mix2s防水吗(Xiaomi)