1. 程式人生 > >最長公共子序列求解演算法及程式碼實現

最長公共子序列求解演算法及程式碼實現

問題描述:
  最長公共子序列問題是在2個序列集合中,查詢最長的公共子序列。
  比如字串:
  s1="ABCDE" s2="ACEF"
  那麼字串s1與字串s2的最長公共子序列就是"ACE"
演算法實現:
  利用動態規劃的方法實現(也叫打表法):2個字串陣列X[m]、Y[n]儲存2個序列集合。用一個輔助二維陣列,這個二維陣列的L[i][j]儲存的是X[0…i]和Y[0…j]中最長公共子序列的長度。

  L[m][n]的值就是lcs的長度。
解得構造:
  這裡構造解結構的時候和演算法導論裡的不一樣,書裡採用的是遞迴的方法構造,這裡是採用了雙指標遍歷的方法也用到了輔助陣列,但是輔助陣列長度等於lcs的長度比書裡的b陣列要小。
  為什麼能這樣做呢?也就是不用b陣列儲存一下“該怎麼走”,我們怎麼找到“路”,也就是lcs呢?別忘了b陣列是怎麼產生的!他是根據L陣列的資訊產生的。因為L陣列的資訊就告訴了我們“怎麼走”,所以可以不要輔助陣列b。
c++程式碼實現:

/* Dynamic Programming implementation of LCS problem */
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;

/* L[i][j] store the length of LCS of X[0..i-1] and Y[0..j-1]*/
void lcsLength( int L[][100], char *X, char *Y, int m, int n )
{
    /* Following steps build L[m+1][n+1] in bottom up fashion. Note
        that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */
for (int i=0; i<=m; i++) { for (int j=0; j<=n; j++) { if (i == 0 || j == 0) L[i][j] = 0; else if (X[i-1] == Y[j-1]) L[i][j] = L[i-1][j-1] + 1; else L[i][j] = max(L[i-1][j], L[i][j-1]); } } } /*print the length of LCS and put out LCS */
void printLcs(int L[][100], char *X, char *Y, int m, int n){ // Following code is used to print LCS // L[m][n] stored the length of LCS int index = L[m][n]; // Create a character array to store the lcs string char lcs[index+1]; lcs[index] = '\0'; // Set the terminating character // Start from the right-most-bottom-most corner and // one by one store characters in lcs[] int i = m, j = n; while (i > 0 && j > 0) { // If current character in X[] and Y are same, then // current character is part of LCS if (X[i-1] == Y[j-1]) { lcs[index-1] = X[i-1]; // Put current character in result char array i--; j--; index--; // reduce values of i, j and index } // If not same, then find the larger of two and // go in the direction of larger value // when add'=',the result is BCBA, just like the book;when it has no '=', the result is BDAB else if (L[i-1][j] >=L[i][j-1]) i--; else j--; } // Print the length of lcs and lcs cout<<"The length of LCS is "<<L[m][n]<<endl; cout << "LCS of " << X << " and " << Y << " is " << lcs; } /* Driver program to test above function */ int main() { char X[] = "ABCBDAB"; char Y[] = "BDCABA"; int m = strlen(X); int n = strlen(Y); int L[100][100]; lcsLength(L, X, Y, m, n); printLcs(L,X,Y,m,n); return 0; }

注:

  • 構造解得時候只能打印出一個lcs,可能存在多個lcs序列。
  • 這裡L陣列是100*100的,要保證100>=max{m,n}