最长公共子序列(LCS)简介

基本概念

一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列(The longest common subsequence)
最长公共子序列中的元素在原序列中不一定是连续的。许多与数学、算法、随机矩阵理论(random matrix theory)、表示论相关的研究都会涉及最长公共子序列。


求解思路

比如说有两个随机数列,1 9 2 8 2 7 和 3 9 2 8 6 6,则它们的最长公共子序列便是9 2 8;9 1 2 7 8 2 和3 9 2 8 6 6的最长公共子序列也是9 2 8。
注意和最长公共子串(Longest Common Substirng)的区别,子串是必须连续的,而子序列不然。


我们可以递归的解决这个问题:
1.当两个串末尾相同时,那么最后的公共子序列便是删去末尾的两个串再求子问题+末尾字符
2.当末尾不同时,考虑一个删一个不删的两种情况,也是相同的子问题,取两者较长者。

代码示例:(string)

string lcs(string a,string b)
{
    if(a.length()==0||b.length()==0) return "";
    else if(a[a.length()-1]==b[b.length()-1]) return lcs(a.substr(0,a.length()-1),b.substr(0,b.length()-1))+a[a.length()-1];
    else{
        string t1=lcs(a.substr(0,a.length()-1),b);
        string t2=lcs(a,b.substr(0,b.length()-1));
        if(t1.length()>t2.length()) return t1;
        else return t2;
    }
}

虽然递归可以方便的求出子序列长度及子序列,但是递归在时间和空间上消耗较大,可以采用从短往长的方法递推(思路相同),采用数组存储字符串。具体见下面例题


例题 Poj 1458

题意:
求解最长公共子序列的长度

代码示例:

#include<iostream>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;

const int maxn=1000;

char str1[maxn];
char str2[maxn];
int dp[maxn][maxn];

int solve()
{
    int len1=strlen(str1);
    int len2=strlen(str2);
    int i,j;
    for(int i=0;i<=len1;++i) dp[i][0]=0;//无公共子序列
    for(int i=0;i<=len2;++i) dp[0][i]=0;

    for(int i=0;i<len1;++i)
        for(j=0;j<len2;++j){
            if(str1[i]==str2[j]) dp[i+1][j+1]=dp[i][j]+1;
            else{
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
            }
        }
    return dp[len1][len2];
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>str1>>str2){
        cout<<solve()<<endl;
    }
    return 0;
}

本题只要求解长度,如果需要具体序列,可以沿着[len1][len2]向左上寻找(逆着的过程),如果有多种走法,则说明存在不同位置选择的最长公共子序列。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值