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

来源:互联网 发布:淘宝客单页网站源码 编辑:程序博客网 时间:2024/06/05 09:22

基本概念

一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列(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]向左上寻找(逆着的过程),如果有多种走法,则说明存在不同位置选择的最长公共子序列。

原创粉丝点击