码迷,mamicode.com
首页 > 其他好文 > 详细

最长公共子序列(LCS)

时间:2014-09-23 11:33:34      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   div   

  以前一直不懂LCS问题,然而找工作被LCS折磨的,与那个公司无缘了。

  最长公共子序列问题是一道经典的动态规划问题,最长公共子序列问题也有最优子结构。

即:Xi<x1, x2,..., xi>即X序列的前i个字符(1<=i<=m),Yj<y1, y2,..., yj)即Y序列的前j个序列(1<=j<=n);假设Z<z1,z2,...,Zk>属于LCS(X,Y);

若:xm==yn(最后一个字符相同),则不难用反证法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有zk = xm = yn 且显然有Zk-1∈LCS(Xm-1 , Yn-1)即Z的前缀Zk-1是Xm-1与Yn-1的最长公共子序列。此时,问题化归成求Xm-1与Yn-1的LCS(LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1)的长度加1)。

若:xm≠yn,则亦不难用反证法证明:要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。由于zk≠xm与zk≠yn其中至少有一个必成立,若zk≠xm则有Z∈LCS(Xm-1 , Y),类似的,若zk≠yn 则有Z∈LCS(X , Yn-1)。此时,问题化归成求Xm-1与Y的LCS及X与Yn-1的LCS。LCS(X , Y)的长度为:max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}。

由于上述当xm≠yn的情况中,求LCS(Xm-1 , Y)的长度与LCS(X , Yn-1)的长度,这两个问题不是相互独立的:两者都需要求LCS(Xm-1,Yn-1)的长度。另外两个序列的LCS中包含了两个序列的前缀的LCS,故问题具有最优子结构性质考虑用动态规划法。

    也就是说,解决这个LCS问题,你要求三个方面的东西:1、LCS(Xm-1,Yn-1)+1;2、LCS(Xm-1,Y),LCS(X,Yn-1);3、max{LCS(Xm-1,Y),LCS(X,Yn-1)}

由上述可以得出递归公式:

bubuko.com,布布扣

 

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
enum decreaseDir {kInit = 0, kLeft, kUp, kLeftUp};
string ret;
void LCS_Print(vector<vector<int> > &dir, const char *str1, const char *str2, int row, int col)
{
    if(str1 == NULL || str2 == NULL)
        return;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if(len1 == 0 || len2 == 0 || !(row < len1 && col < len2 ))
        return;
    if(dir[row][col] == kLeftUp)
    {
        if(row > 0 && col > 0)
            LCS_Print(dir, str1, str2, row - 1, col -1);
        ret.push_back(str1[row]);
    }
    else if(dir[row][col] == kUp)
    {
        if(row > 0)
            LCS_Print(dir, str1, str2, row - 1, col);
    }
    else if(dir[row][col] == kLeft)
    {
        if(col > 0)
            LCS_Print(dir, str1, str2, row, col -1);
    }
}
int LCS(const char *str1, const char *str2)
{
    if(!str1 || !str2)
        return 0;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    if(!len1 || !len2)
        return 0;
    int i, j;
    vector<vector<int> > dp(len1, vector<int>(len2, 0));
    vector<vector<int> > dir(len1, vector<int>(len2, 0));
    for(int i = 0; i < len1; i++)
    {
        for(int j = 0; j < len2; j++)
        {
            if(i == 0 || j == 0)
            {
                if(str1[i] == str2[j])
                {
                    dp[i][j] = 1;
                    dir[i][j] = kLeftUp;
                }
                else
                {
                    if(i > 0)
                    {
                        dp[i][j] = dp[i-1][j];
                        dir[i][j] = kUp;
                    }
                    if(j > 0)
                    {
                        dp[i][j] = dp[i][j-1];
                        dir[i][j] = kLeft;
                    }
                }
            }
            else if(str1[i] == str2[j])
            {
                dp[i][j] = dp[i-1][j-1] + 1;
                dir[i][j] = kLeftUp;
            }
            else if(dp[i-1][j] > dp[i][j-1])
            {
                dp[i][j] = dp[i-1][j];
                dir[i][j] = kUp;
            }
            else
            {
                dp[i][j] = dp[i][j-1];
                dir[i][j] = kLeft;
            }
        }
    }
    LCS_Print(dir, str1, str2, len1 - 1, len2 - 1);
    return dp[len1-1][len2-1];
}
int main()
{
    const char *str1 = "abcde";
    const char *str2 = "acde";
    ret.clear();
    int longest = LCS(str1, str2);
    cout << "longest = " << longest << endl;
    cout << "ret = " << ret << endl;
    return 0;
}

 

最长公共子序列(LCS)

标签:style   blog   http   color   io   os   ar   for   div   

原文地址:http://www.cnblogs.com/awy-blog/p/3987607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!