日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LCS最长公共子串

發(fā)布時間:2023/11/30 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LCS最长公共子串 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

問題介紹

LCS問題(longest common subsequence problem)指的是求解兩個字符串最長公共子序列問題。這里的子序列是可以不連續(xù)的。LCS問題廣泛地出現(xiàn)在計算生物學(xué)中(DNA序列、系統(tǒng)生成樹等等)。這里介紹如何解決LCS問題,以及算法的正確性證明和性能分析。

解決方案

假設(shè)需要求解串X,Y的LCS,其中|X|=n,|Y|=m,c[i][j]表示X[1…i]和Y[1…j]的LCS長度,z[1…k]表示X[1…i]和Y[1…j]的LCS,k=c[i][j],則問題就是求解c[n][m]和z[c[n][m]]c[n][m]和z[c[n][m]]c[n][m]z[c[n][m]]

樸素的想法是,按照問題的要求,我們可以得到串X的所有子串,共有2n2^n2n個,然后判斷該子串是否出現(xiàn)在串Y中,每次判斷都需要遍歷串Y,因此時間復(fù)雜度為O(2n?m)O(2^n*m)O(2n?m),這顯然是我們不能接受的復(fù)雜度。

為了解決這個問題,我們需要得到該問題的一些性質(zhì):

定理:

ifX[i]==Y[j]:c[i][j]=c[i?1][j?1]+1if X[i]==Y[j]:c[i][j]=c[i-1][j-1]+1 ifX[i]==Y[j]:c[i][j]=c[i?1][j?1]+1

otherwise:c[i][j]=max(c[i?1][j],c[i][j?1])otherwise:c[i][j]=max(c[i-1][j],c[i][j-1]) otherwisec[i][j]=max(c[i?1][j],c[i][j?1])

引理1:如果X[i]==Y[j],則z[c[i][j]]=X[i]z[c[i][j]]=X[i]z[c[i][j]]=X[i]

證明:如果z[c[i][j]]≠X[i]z[c[i][j]]\neq X[i]z[c[i][j]]?=X[i],且X[i]==Y[j],那么不妨將X[i]加入到LCS中,c[i][j]c[i][j]c[i][j]加一,因此z[1..c[i][j]]z[1..c[i][j]]z[1..c[i][j]]不是LCS,與條件矛盾,證畢。

引理2:如果X[i]==Y[j],則X[i-1]和Y[j-1]的LCS是z[1..c[i][j]?1]z[1..c[i][j]-1]z[1..c[i][j]?1]

證明:X[i-1]和Y[j-1]的LCS不是z[1..c[i][j]?1]z[1..c[i][j]-1]z[1..c[i][j]?1],則使用X[i-1]和Y[j-1]的LCS替換z[1..c[i][j]?1]z[1..c[i][j]-1]z[1..c[i][j]?1]后再加上X[i]會得到X[i]和Y[j]的一個更長的一個LCS,與條件矛盾,證畢。引理2這里展示了問題的最優(yōu)子結(jié)構(gòu)

引理3:如果兩個串的LCS包含兩個串的末尾元素X[i]和Y[j],則這兩個元素相等

證明:如果X[i]不等于Y[j],則在LCS中,X[i]對應(yīng)Y[j’],j’<j,Y[j]對應(yīng)X[i’],i’<i,這不符合公共子串保留原串順序的性質(zhì),矛盾。證畢。

當(dāng)X[i]==Y[j]時,由引理1保證了此時的LCS是串X[i]對應(yīng)串Y[j’],j′?jj'\leqslant jj?j,對于j′<jj' < jj<j的情況,我們不妨用jjj來替換j′j'j,這樣也不會對LCS的長度有什么影響,然后由引理2,c[i][j]=c[i?1][j?1]+1c[i][j]=c[i-1][j-1]+1c[i][j]=c[i?1][j?1]+1

對于第二個條件,因為X[i]≠\neq?=Y[j],那么此時的LCS要么屬于c[i?1][j]c[i-1][j]c[i?1][j],要么屬于c[i][j?1]c[i][j-1]c[i][j?1]

假設(shè)都不屬于,那么此時的LCS一定包含了c[i?1][j]c[i-1][j]c[i?1][j]中沒有的元素X[i]和c[i][j?1]c[i][j-1]c[i][j?1]中沒有的元素Y[j],由引理3,矛盾。

在證明了上述定理以后我們可以根據(jù)該式子計算LCS:

  • 遞歸法
  • int LCS(string& x, string &y,int n,int m) {if(-1==n || -1==m) return 0;if(x[n]==y[m]) return LCS(x, y, n-1, m-1)+1;else return max(LCS(x, y, n-1, m), LCS(x, y, n, m-1)); }

    性能分析

    分析遞歸樹,最壞的情況是每次x[n]!=y[m],那么會得到一個高度為n+m的二叉樹,時間復(fù)雜度為O(2n+m)O(2^{n+m})O(2n+m),空間復(fù)雜度為O(n+m)O(n+m)O(n+m)

  • 備忘錄方法(記憶化搜索)
  • 分析上面時間復(fù)雜度我們發(fā)現(xiàn),在搜索過程中很多的子問題都是一模一樣的,也就是具有重疊子問題性質(zhì),因此我們不妨每計算出一個子問題的結(jié)果就進(jìn)行一次記錄,后面再次需要求解結(jié)果的時候就不需要再計算,而是直接返回結(jié)果。

    int LCS(string& x, string &y,int n,int m,int *c) {if(-1==n || -1==m) return 0;if(c[n*y.size()+m]) return c[n*y.size()+m];int ret;if(x[n]==y[m]) ret = LCS(x, y, n-1, m-1, c)+1;else ret = max(LCS(x, y, n-1, m, c), LCS(x, y, n, m-1, c));return c[n*y.size()+m]=ret; }int main() {string X,Y;cout<<"請輸入字符串X:"; cin>>X;cout<<"請輸入字符串Y:"; cin>>Y;int* c = new int[X.size()*Y.size()+10]();cout<<"字符串X和Y的LCS的長度為"<<LCS(X, Y, X.size(), Y.size(), c)<<endl;delete c;return 0; }

    性能分析

    我們可以把對結(jié)果是否已經(jīng)計算出的判斷和返回答案的耗費記錄在調(diào)用該狀態(tài)答案的耗費上,把實際結(jié)果的計算記錄在該狀態(tài)中,則最壞情況下每種狀態(tài)都要計算出來,因此時間復(fù)雜度為O(nm)O(nm)O(nm),空間復(fù)雜度為O(nm)O(nm)O(nm)

  • 自底向上計算(動態(tài)規(guī)劃法)
  • 我們觀察計算的過程,如果我們對狀態(tài)空間按照從左向右從上向下進(jìn)行求解,就可以計算出所有的答案

    int LCS(string& x, string &y,int n,int m,int *c) {for(int i=1; i<=x.size(); ++i){for(int j=1;j<=y.size(); ++j){if(x[i-1] == y[j-1])c[i*y.size()+j]=c[(i-1)*y.size()+j-1]+1;elsec[i*y.size()+j]=max(c[(i-1)*y.size()+j], c[(i)*y.size()+j-1]);}}return c[n*y.size()+m]; }

    性能分析

    時間復(fù)雜度O(nm)O(nm)O(nm),因為訪問的是連續(xù)的內(nèi)存空間,因此這里的O(nm)O(nm)O(nm)應(yīng)該比上面小。空間復(fù)雜度O(nm)O(nm)O(nm),如果使用滾動數(shù)組還能夠?qū)⒖臻g復(fù)雜度降低為O(min(n,m))O(min(n,m))O(min(n,m))如果不使用滾動數(shù)組,想要得到完整的LCS串需要在計算的時候設(shè)置指針,最后進(jìn)行回溯。如果使用滾動數(shù)組,需要使用分治法得到LCS串

    回溯如圖:

    總結(jié)

    以上是生活随笔為你收集整理的LCS最长公共子串的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。