LCS詳解

LCS是什么

LCS是Longest Common Subsequence的縮寫,即最長公共子序列。一個序列,如果是兩個或者多個序列的子序列,并且是所有子序列中最長的,則為最長公共子序列。(有序但不連續(xù)也為子序列)

  • 序列 13456 和 345674 的最長公共子序列為 3456
  • 序列 ABDBC 和 BCDBA 的最長公共子序列為 BDB

LCS可以用來做什么

  • 生物學上用來進行基因序列比對,以推測序列的結(jié)構(gòu)、功能和演化過程
  • 用來描述兩段文字的”相似性“,可以用來辨別是不是抄襲

怎么計算LCS

  • 暴力窮舉法

    就是把兩個序列所有的子序列都列出來,然后一一進行比較。

    假定字符串 A 和 B 的長度分別為 n 和 m,那么 A 共有 2^n-1 個子序列,B 共有 2^m-1 個子序列,然后將任意兩個進行一一比較,最后得出 A 和 B 的最長公共子序列。這種算法的時間復雜度是 O(2^{n+m}) ,復雜度太高,當然不推薦使用。

  • 動態(tài)規(guī)劃法

    記:

    字符串 A ,長度為 n ,從 1 開始;字符串 A ,長度為 n ,從 1 開始。

    A_i=<A_1,A_2,...Ai> 即 A 序列的前 i 個字符 (1\leq i \leq n) (A_i 計做”字符串 A 的 i 前綴)

    B_j=<B_1,B_2,...Bj> 即 B 序列的前 j 個字符 (1\leq j \leq m) (B_j 計做”字符串 B 的 j 前綴)

    如果 A_n=B_m (最后一個字符相同),那么 A 和 B 的最長公共子序列 C 的最后一位 C_k=A_n=B_m ,那么 LCS(A,B)=LCS(A_n-1,B_m-1)+A_n

    如果 A_n\not=B_m ,那么他們的最長公共子序列 C 要么是 LCS(A_{n-1},B_m) ,要么是 LCS(A_n,B_{m-1}) ,所以 LCS(A,B)=max\{LCS(A_{n-1},B_m),LCS(A_n,B_{m-1})\}

    1 2 3 4 5 6 7
    A B D C A B A
    B A B C B D A B

    A_3=B_3= 'C' 那么 LCS(BDC,ABC)=LCS(BD,AB)+'C'

    A_5=B_4='B' 那么 LCS(BDCAB,ABCB)=LCS(BDCA,ABC)+'B'

    A_2\not=B_2 那么 LCS(BD,AB)=max\{LCS(B,AB),LCS(BD,A)\}

    A_4\not=B_5 那么 LCS(BDCA,ABCBD)=max\{LCS(BDC,ABCBD),LCS(BDCA,ABCB)\}

    由以上可以得出

LCS(A_n,B_m)=\begin{cases}LCS(A_{n-1},B_{m-1}+A_n) \quad \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \quad A_n=B_m\\ max\{LCS(A_{n-1},B_m),LCS(A_n,B_{m-1})\} \quad A_n\not=B_m\end{cases}

使用動態(tài)規(guī)劃法求解

首先上一幅圖

0_1313577405FsRn.gif

記一個二維數(shù)組 c[m,n]c[i,j] 的值為 x_iy_j 的最長公共子序列的長度,然后不難得出當 i=0j=0 的時候 X_iY_j 的最長公共子序列的長度。然后通過動態(tài)規(guī)劃法的公式得出
c(i,j)=\begin{cases}0 \quad \quad \quad \quad i=0,j=0 \\ c(i-1,j-1) \quad \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \quad i>0,j>0,x_i=y_j\\ max\{c(i-1,j),c(i,j-1))\} \quad i>0,j>0,x_i\not=y_j\end{cases}
然后我們通過公式計算 c(1,1) ,因為 x_1y_1 不相等,得出 c(1,1)=max \{ c(0,1),c(1,0) \}=0 。然后依次計算,就會得到圖中的值,然后得出 xy 的最長公共子序列的長度為4。我們在計算的時候會發(fā)現(xiàn)一個規(guī)律:當 x_i=y_j 的時候 c(i,j) 的值為左上角格子的數(shù)加1;當 x_i\not=y_j 的時候 c(i,j) 的值為左側(cè)格子和上邊格子中的較大的一個。

代碼實現(xiàn)

import sys

str1 = sys.argv[1]
str2 = sys.argv[2]

len1 = len(str1)
len2 = len(str2)

maxChildLen = 0

lcs_ss = [[0 for i in range(len2 + 1)] for j in range(len1 + 1)]

for i in range(1, len1 + 1):
    for j in range(1, len2 + 1):
        if str1[i-1] == str2[j-1]:
            lcs_ss[i][j] = lcs_ss[i-1][j-1] + 1
        else:
            lcs_ss[i][j] = max(lcs_ss[i-1][j], lcs_ss[i][j-1])

maxChildLen = lcs_ss[len1][len2]

print("str1: %s" % str1)
print("str2: %s" % str2)
print("LCS: %s" % maxChildLen)

隨便輸入兩個字符串,然后觀察打印結(jié)果

str1: acedbae
str2: becadeac
LCS: 3

Process finished with exit code 0

若有任何問題,懇請不吝指正。


歡迎關(guān)注公眾號:「努力給自己看」

二維碼
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 專業(yè)考題類型管理運行工作負責人一般作業(yè)考題內(nèi)容選項A選項B選項C選項D選項E選項F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚閱讀 10,670評論 0 13
  • 動態(tài)規(guī)劃(Dynamic Programming) 本文包括: 動態(tài)規(guī)劃定義 狀態(tài)轉(zhuǎn)移方程 動態(tài)規(guī)劃算法步驟 最長...
    廖少少閱讀 3,663評論 0 18
  • 算法思想貪心思想雙指針排序快速選擇堆排序桶排序荷蘭國旗問題二分查找搜索BFSDFSBacktracking分治動態(tài)...
    第六象限閱讀 4,909評論 0 0
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,727評論 0 5
  • 清晨,貓寶寶在媽媽的輕吻中醒來,開始了一天的探險:花園里有什么在等著它?它能爬上最喜歡的大樹的樹頂嗎?那個神...
    久久王Anne閱讀 740評論 0 2

友情鏈接更多精彩內(nèi)容