最长公共子序列求解算法及代码实现

问题描述:
  最长公共子序列问题是在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}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值