最长公共子序列(LCS)问题

Posted home普通的人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长公共子序列(LCS)问题相关的知识,希望对你有一定的参考价值。

最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续。

1、序列str1和序列str2
 
  ·长度分别为m和n;
  ·创建1个二维数组L[m.n];
    ·初始化L数组内容为0
    ·m和n分别从0开始,m++,n++循环:
       - 如果str1[m] == str2[n],则L[m,n] = L[m - 1, n -1] + 1;
       - 如果str1[m] != str2[n],则L[m,n] = max{L[m,n - 1],L[m - 1, n]}
    ·最后从L[m,n]中的数字一定是最大的,且这个数字就是最长公共子序列的长度
    ·从数组L中找出一个最长的公共子序列
 
   2、从数组L中查找一个最长的公共子序列
 
   i和j分别从m,n开始,递减循环直到i = 0,j = 0。其中,m和n分别为两个串的长度。
  ·如果str1[i] == str2[j],则将str[i]字符插入到子序列内,i--,j--;
  ·如果str1[i] != str[j],则比较L[i,j-1]与L[i-1,j],L[i,j-1]大,则j--,否则i--;(如果相等,则任选一个)
 

我们可以得到其中公共子串:B C B A 和 B D A B。

 

#include <iostream>
#define N 1000
using namespace std;

//c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度
int c[N][N];
//flag[i][j]标记是那种子问题
//flag[i][j]==0为str1[i]==str2[j]
//flag[i][j]==1为c[i-1][j]>=s[i][j-1]
//flag[i][j]==-1为c[i-1][j]<s[i][j-1]
int flag[N][N];

int getLCSlength(string str1, string str2)
{
    int len1 = str1.size();
    int len2 = str2.size();
    for (int i = 0; i <= len1; i++)
    {
        for (int j = 0; j <= len2; j++)
        {
            if (i == 0 || j == 0)
                c[i][j] = 0;
            else if (str1[i - 1] == str2[j - 1])
            {
                c[i][j] = c[i - 1][j - 1] + 1;
                flag[i][j] = 0;
            }
            else if (c[i - 1][j] >= c[i][j - 1]){
                c[i][j] = c[i - 1][j];
                flag[i][j] = 1;
            }
            else{
                c[i][j] = c[i][j - 1];
                flag[i][j] = -1;
            }
        }
    }
    return c[len1][len2];
}

void getLCS(string s1, string s2,int len,char *lcs)
{
    int i = s1.size();
    int j = s2.size();
    while(i&&j)
    {
        if(flag[i][j]==0)
        {
            lcs[--len] = s1[i-1];
            i--;
            j--;
        }
        else if(flag[i][j]==1) //往上
            i--;
        else if(flag[i][j]==-1)//往左
            j--;
    }

}

int main()
{
    string str1,str2,lcs;
   char lcs[N];
    cout<<"请输入字符串1:"<<endl;
    cin>>str1;
    cout<<"请输入字符串2:"<<endl;
    cin>>str2;

    int lcsLen = getLCSlength(str1,str2);
    cout<<"最长公共子序列长度:"<<lcsLen<<endl;


    getLCS(str1,str2,lcsLen,lcs);
    cout<<"最长公共子序列为:";
    for(int i=0;i<lcsLen;i++)
        cout<<lcs[i];
    return 0;
}

 

以上是关于最长公共子序列(LCS)问题的主要内容,如果未能解决你的问题,请参考以下文章

最长公共子序列(LCS),求LCS长度和打印输出LCS

每日一题-——最长公共子序列(LCS)与最长公共子串

最长公共子序列(LCS)和逆LCS问题求解

最长公共子序列(LCS)

最长公共子串和最长公共子序列(LCS问题)

最长公共子串和最长公共子序列(LCS问题)