动态规划之最长公共子序列

给定两个序列x和y,称z是x和y的公共子序列,如果z既是x的子序列,又是y的子序列;最长的公共子序列称作最长公共子序列LCS(longest common subsequence)。

解题思路

(1)LCS的最优子结构
设zk是xm和yn的一个LCS,则,如果x和y的最后一个元素相同,则z中去掉最后一个元素之后zk-1仍为xm-1和yn-1的LCS。
如果xm!=yn,若zk!=xm,则z是xm-1和y的一个LCS,若zk!=yn,则z是xm和yn-1的LCS。

(2)一个递归解
设c[i][j]为序列xi和yj的一个LCS的长度,则有:

expression condition
c[i][j]=0 

i=0或j=0
c[i][j]=c[i−1][j−1]+1 

xi=yj且i,j>0
c[i][j]=max(c[i][j−1],c[i−1][j]) 

xi!=yj且i,j>0

(3)计算LCS的长度

实现代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int lenLCS(const char *ch1, const char *ch2, int len1, int len2, int **c)
{
    for (int i = 0; i <= len1; i++)
    {
        c[i][0] = 0;
    }
    for (int i = 0; i <= len2; i++)
    {
        c[0][i] = 0;
    }

    for (int i = 1; i <= len1; i++)
    {
        for (int j = 1; j <= len2; j++)
        {
            if (ch1[i-1] == ch2[j-1])
            {
                c[i][j] = c[i-1][j-1] + 1;
            }
            else
            {
                if (c[i-1][j] >= c[i][j-1])
                {
                    c[i][j] = c[i-1][j];
                }
                else
                {
                    c[i][j] = c[i][j-1];
                }
            }
        }
    }

//    for (int i = 0; i <= len1; i++)
//        for (int j = 0; j <= len2; j++)
//            if (j == len2) printf("%d\n", c[i][j]);
//            else printf("%d ", c[i][j]);

    return c[len1][len2];
}

void printLCS(const char *ch1, const char* ch2, int len1, int len2, int **c)
{
    int i = len1;
    int j = len2;
    while (c[i][j] > 0)
    {
        if (ch1[i-1] == ch2[j-1])
        {
            cout<<ch1[i-1];
            i--;
            j--;
        }
        else
        {
            if (c[i][j] == c[i-1][j])
            {
                i--;
            }
            else
            {
                j--;
            }
        }
    }
}

int main()
{
    char *ch1 = "ACCGGTCGAGTGCGCGGAAGCCGGCCGAA";
    char *ch2 = "GTCGTTCGGAATGCCGTTGCTCTGTAAA";
    int len1 = strlen(ch1);
    int len2 = strlen(ch2);
    int **c = new int*[len1 + 1];
    for (int i = 0; i <= len1; i++)
    {
        c[i] = new int[len2 + 1];
    }

    cout<<lenLCS(ch1, ch2, len1, len2, c)<<endl;
    printLCS(ch1, ch2, len1, len2, c);

    for (int i = 0; i <= len1; i++)
    {
        delete [] c[i];
    }
    delete [] c;
    return 0;
}

不连续情况的转移方程:

扩展到连续情况,转移方程为:

实现代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

int fun(char *ch1, char *ch2, int len1, int len2, int **c)
{
    for (int i = 0; i <= len1; i++)
    {
        c[i][0] = 0;
    }
    for (int j = 0; j <= len2; j++)
    {
        c[0][j] = 0;
    }

    int maxlen = 0;
    for (int i = 1; i <= len1; i++)
    {
        for (int j = 1; j <= len2; j++)
        {
            if (ch1[i-1] == ch2[j-1])
            {
                c[i][j] = c[i-1][j-1] + 1;
            }
            else
            {
                c[i][j] = 0;
            }

            maxlen = max(maxlen, c[i][j]);
        }
    }

    return maxlen;
}

int main()
{
    char *ch1 = "acaccbabb";
    char *ch2 = "acbac";
    int len1 = strlen(ch1);
    int len2 = strlen(ch2);
    int **c = new int*[len1 + 1];
    for (int i = 0; i <= len1; i++)
    {
        c[i] = new int[len2 + 1];
    }
    int maxlen = fun(ch1, ch2, len1, len2, c);
    printf("The max length is : %d\n", maxlen);

    for (int i = 0; i <= len1; i++)
    {
        delete [] c[i];
    }
    delete [] c;
}

转自:http://blog.csdn.net/foreverling/article/details/44679139

时间: 2024-08-02 22:10:37

动态规划之最长公共子序列的相关文章

动态规划解最长公共子序列(LCS)问题 (附可打印LCS完整代码)

一.动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. 二.问题:求两字符序列的最长公共字符子序列(LCS) 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的

算法知识之最长公共子序列问题(动态规划)

最近朋友让帮做个关于动态规划的最长公共子序列的问题,翻看以前的笔记并完成该题后,顺便写这样一篇文章,希望对大家有所帮助,同时也帮助自己回顾该知识点. 一.最长公共子序列的定义 子序列:若给定序列X={x1,x2,-,xm},则另一序列Z={z1,z2,-,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,-,ik}使得对于所有j=1,2,-,k有:zj=xij.公共子序列:给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列.最长公共子序列:给

c-动态规划求最长公共子序列,存在多个解时只能输出一个。

问题描述 动态规划求最长公共子序列,存在多个解时只能输出一个. //求取所有的最长公共子序列 不知道代码哪里写错了,也只有一个币能悬赏,希望有空的大神们帮忙看看,纠结好久了不知道怎么改. #include using namespace std; const int X=100, Y= 100; //串的最大长度 char result[X+1]; //用于保存结果 int count= 0; //用于保存公共最长公共子串的个数 /*功能:计算最优值 *参数: x:字符串x y:字符串y b:标

第十五章 动态规划——最长公共子序列

1.基本概念 一个给定序列的子序列就是该给定序列中去掉零个或者多个元素的序列.形式化来讲就是:给定一个序列X={x1,x2,--,xm},另外一个序列Z={z1.z2.--,zk},如果存在X的一个严格递增小标序列<i1,i2--,ik>,使得对所有j=1,2,--k,有xij = zj,则Z是X的子序列.例如:Z={B,C,D,B}是X={A,B,C,B,D,A,B}的一个子序列,相应的小标为<2,3,5,7>.从定义可以看出子序列直接的元素不一定是相邻的. 公共子序列:给定两个

经典面试题:最长公共子序列

1.问题描述: 什么是最长公共子序列呢?好比一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列.     举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5 5.     注意最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一

Ruby实现的最长公共子序列算法

  这篇文章主要介绍了Ruby实现的最长公共子序列算法,本文直接给出实现代码,需要的朋友可以参考下 最长公共子序列,LCS,动态规划实现. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #encoding: utf-8 #author:

经典算法题每日演练——第四题 最长公共子序列

一: 作用        最长公共子序列的问题常用于解决字符串的相似度,是一个非常实用的算法,作为码农,此算法是我们的必备基本功. 二:概念      举个例子,cnblogs这个字符串中子序列有多少个呢?很显然有27个,比如其中的cb,cgs等等都是其子序列,我们可以看出 子序列不见得一定是连续的,连续的那是子串.      我想大家已经了解了子序列的概念,那现在可以延伸到两个字符串了,那么大家能够看出:cnblogs和belong的公共子序列吗? 在你找出的公共子序列中,你能找出最长的公共子

动态规划法——最长公共子序列问题

       这个题当初始终看不下去的原因就是当初误解了什么叫最长公共子序列,还一度以为这个题有问题,其实如果明白了什么叫最长公共子序列,也就解决了一半的问题.   什么是最长公共子序列?      什么是最长公共子序列呢?举个简单的例子吧,一个数列S,若分别是两个或多个已知序列的子序列,且是所有符合条件序列中最长的,则S称为已知序列的最长公共子序列.      注意区别:                  最长公共子串和最长公共子序列          最长公共子串(Longest Commo

最长公共子序列LCS

时间限制:1 秒 空间限制:65536 KB 分值: 0 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列. Input 第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000) Output 输出最长的子序列,如果有多个,随意输出1个. Input 示例 abcicba abdkscab Output 示例 abca 动态