動態規划算法2——最長公共子序列


本文作者frankchenfu,blogs網址http://www.cnblogs.com/frankchenfu/,轉載請保留此文字。

今天,我給大家帶來的是“最長公共子序列”(LCS)的講解。限於水平,這里僅介紹O(nm)算法。

最長公共子序列其實是很好理解的。

顧名思義,給出多個(這里暫且只考慮兩個)序列,求他們的最長公共子序列,就是在這兩個序列中分別刪去一些的字符,得到兩個相同的序列,使得這兩個相同的序列最長。

當然上面是我自己用比較好理解的方法寫的,關於某些“百科”上的解釋就是“一個序列S,如果分別是兩個或多個已知序列的子序列,且是所有符合此條件序列中最長的,則S稱為已知序列的最長公共子序列。而最長公共子串(要求連續)和最長公共子序列是不同的 ”。

這里要先牽扯到一個“子序列”的問題。子序列就是一個序列中,刪去一些字符后剩下部分。例如,“abc”就是“axbyc”的一個子序列,他相應的子序列在原序列的下標就是“1,3,5”。

再比如,

令字串A為“abcdef”,字串B為“defghi”,那么他們的最長公共子序列是什么呢?

顯然,是“def”。因為子串“d”、“e”和“f”長度均為1,子串“de”、“ef”和“df”均為2,只有“def”長度為3。

所以,現在,我們給出兩個序列,求他們的最長公共子序列。

 

【輸入格式】

共兩行。每行給出一個長度不超過200的字符串。

【輸出格式】

共兩行。第一行一個非負整數表示最長公共子序列的長度。第二行輸出這個子序列(若有多解,任意輸出一個)。

【輸入樣例】

ABCBDAB

BDCABA

【輸出樣例】

4

BCBA

【分析】

看到題目,肯定有人會想到搜索。可是搜索並不能解決一切問題。我們看到搜索是指數級的時間復雜度——你給10秒能不能算完是問題!我們需要設計一個略微高效的算法——嘗試使用動態規划。但是在此之前,我們先來看一些有效分析,來驗證我們的猜想是否正確。

(1)最優子結構性質

這個性質有一個定理,叫LCS的最優子結構性質

這個定理告訴我們,兩個序列的最長公共子序列包含這兩個序列的前綴最長公共子序列,所以這個問題是符合最優子結構性質的。

(2)子問題重疊性質

由最優子結構性質可以推導出該問題具備子問題重疊性質。我們可以依此建立一個計算到目前為止,子序列“最優值”的問題的遞歸關系。用c[i][j]記錄序列X[i]和Y[i]的最長公共子序列的長度,其中當$i=0$或$j=0$時,$c_{i,j}=0$。否則,當$X_i=Y_i$時,$c_{i,j}=c_{i-1,j-1}+1$,當$X_i$≠$Y_i$時,$c_{i,j}=max(c_{i,j-1},c_{i-1,j})$.

這些方法得出的時間復雜度已經滿足200的數據了,不過可以再優化,將體現在代碼中,大家可以自行思考。Cpp代碼如下:

#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
inline int max(int a,int b)
{
    return a>b?a:b;
}
const int MAX=201;
int c[MAX][MAX];
int n,i,j,l1,l2;
char x[MAX],y[MAX];
string z="";
int main()
{
    scanf("%s%s",x,y);
    l1=strlen(x);l2=strlen(y);
    for(i=1;i<=l1;i++)
        for(j=1;j<=l2;j++)
            if(x[i-1]==y[j-1])
                c[i][j]=c[i-1][j-1]+1;
            else
                c[i][j]=max(c[i-1][j],c[i][j-1]);
    printf("%d\n",c[l1][l2]);
    //求LCS長度已完成,若無需求內容,可忽略以下。 
    for(i=l1,j=l2;i&&j;)
        if(x[i-1]==y[j-1])
        {
            z=x[--i]+z;
            j--;
        }
        else
            if(c[i-1][j]>c[i][j-1])
                i--;
            else
                j--;
    printf("%s",z.c_str());//返回C風格可用%s的字符串 
    return 0;
}

希望對大家有所幫助,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM