一、什么是最长公共子序列
   
  什么是最长公共子序列呢?举个简单的例子吧,一个数列S,若分别是两个或多个已知序列的子序列,且是所有符合条件序列中最长的,则S称为已知序列的最长公共子序列。
  举例如下,如:有两个随机数列,1 2 3 4 5 6 和 3 4 5 8 9,则它们的最长公共子序列便是:3 4 5。
 
     最长公共子串(Longest Common Substirng)和最长公共子序列(Longest Common Subsequence,LCS)的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而获得新的序列;也就是说,子串中字符的位置必须是连续的,子序列则可以不必连续。
 
 
 
二、解决方案

<1> 枚举法

这种方法是最简单,也是最容易想到的,当然时间复杂度也是龟速的,我们可以分析一下,刚才也说过了cnblogs的子序列个数有27个 ,延伸一下:一个长度为N的字符串,其子序列有2N个,每个子序列要在第二个长度为N的字符串中去匹配,匹配一次需要O(N)的时间,总共也就是O(N*2N),可以看出,时间复杂度为指数级,恐怖的令人窒息。

<2> 动态规划

最长公共子序列的结构有如下表示:

设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:
   1> 若 xm=yn,则 zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共子序列; 
   2> 若 xm≠yn且 zk≠xm ,则 Z是 Xm-1和 Y的最长公共子序列;
   3> 若 xm≠yn且 zk≠yn ,则 Z是 X和 Yn-1的最长公共子序列;
 
现有两个序列X={x1,x2,x3,...xi},Y={y1,y2,y3,....,yi},设一个C[i,j]: 保存Xi与Yj的LCS的长度,递推方程为:

代码:

    //只能打印一个最长公共子序列
#include <iostream>
using namespace std; const int X = , Y = ; //串的最大长度
char result[X+]; //用于保存结果
int count=; //用于保存公共最长公共子串的个数 /*功能:计算最优值
*参数:
* x:字符串x
* y:字符串y
* b:标志数组
* xlen:字符串x的长度
* ylen:字符串y的长度
*返回值:最长公共子序列的长度
*
*/
int Lcs_Length(string x, string y, int b[][Y+],int xlen,int ylen)
{
int i = ;
int j = ; int c[X+][Y+];
for (i = ; i<=xlen; i++)
{
c[i][]=;
}
for (i = ; i <= ylen; i++ )
{
c[][i]=;
}
for (i = ; i <= xlen; i++)
{
for (j = ; j <= ylen; j++)
{
if (x[i - ] == y[j - ])
{
c[i][j] = c[i-][j-]+;
b[i][j] = ;
}
else if (c[i-][j] > c[i][j-])
{
c[i][j] = c[i-][j];
b[i][j] = ;
}
else if(c[i-][j] <= c[i][j-])
{
c[i][j] = c[i][j-];
b[i][j] = ;
}
}
}
     return c[xlen][ylen];
} void Display_Lcs(int i, int j, string x, int b[][Y+],int current_Len)
{
if (i == || j==)
{
return;
}
if(b[i][j]== )
{
current_Len--;
result[current_Len]=x[i- ];
Display_Lcs(i-, j-, x, b, current_Len);
}
else if(b[i][j] == )
{
Display_Lcs(i-, j, x, b, current_Len);
}
else if(b[i][j]==)
{
Display_Lcs(i, j-, x, b, current_Len);
}
else
{
Display_Lcs(i-,j,x,b, current_Len);
}
} int main(int argc, char* argv[])
{
string x = "ABCBDAB";
string y = "BDCABA";
int xlen = x.length();
int ylen = y.length(); int b[X + ][Y + ]; int lcs_max_len = Lcs_Length( x, y, b, xlen,ylen );
cout << lcs_max_len << endl; Display_Lcs( xlen, ylen, x, b, lcs_max_len ); //打印结果如下所示
for(int i = ; i < lcs_max_len; i++)
{
cout << result[i];
}
cout << endl;
return ;
}

运行结果如下:

BDAB

由于有时并不是只有一个最长公共子序列,所以,对上面的代码进行改进,增加一个数组保存结果等....代码如下所示。

//求取所有的最长公共子序列
#include <iostream>
using namespace std; const int X = , Y = ; //串的最大长度
char result[X+]; //用于保存结果
int cnt = ; //用于保存公共最长公共子串的个数 /*功能:计算最优值
*参数:
* x:字符串x
* y:字符串y
* b:标志数组
* xlen:字符串x的长度
* ylen:字符串y的长度
*返回值:最长公共子序列的长度
*
*/
int Lcs_Length(string x, string y, int b[][Y+],int xlen,int ylen)
{
int i = ;
int j = ; int c[X+][Y+];
for (i = ; i<=xlen; i++)
{
c[i][]=;
}
for (i = ; i <= ylen; i++ )
{
c[][i]=;
}
for (i = ; i <= xlen; i++)
{ for (j = ; j <= ylen; j++)
{
if (x[i - ] == y[j - ])
{
c[i][j] = c[i-][j-]+;
b[i][j] = ;
}
else if (c[i-][j] > c[i][j-])
{
c[i][j] = c[i-][j];
b[i][j] = ;
}
else if(c[i-][j] < c[i][j-])
{
c[i][j] = c[i][j-];
b[i][j] = ;
}
else
{
c[i][j] = c[i][j-]; //或者c[i][j]=c[i-1][j];
b[i][j] = ;
}
}
}
    return c[xlen][ylen];
} /*功能:计算最长公共子序列
*参数:
* xlen:字符串x的长度
* ylen:字符串y的长度
* x :字符串x
* b:标志数组
* current_len:当前长度
* lcs_max_len:最长公共子序列长度
*
*/
void Display_Lcs(int i, int j, string x, int b[][Y+],int current_len,int lcs_max_len)
{
if (i == || j==)
{
for(int s=; s < lcs_max_len; s++)
{
cout << result[s];
}
cout<<endl;
cnt++;
return;
}
if(b[i][j]== )
{
current_len--;
result[current_len]=x[i- ];
Display_Lcs(i-, j-, x, b,current_len,lcs_max_len);
}
else if(b[i][j] == )
{
Display_Lcs(i-, j, x, b,current_len,lcs_max_len);
}
else if(b[i][j]==)
{
Display_Lcs(i, j-, x, b,current_len,lcs_max_len);
}
else
{
Display_Lcs(i,j-,x,b,current_len,lcs_max_len);
Display_Lcs(i-,j,x,b,current_len,lcs_max_len);
}
} int main(int argc, char* argv[])
{
string x = "ABCBDAB";
string y = "BDCABA";
int xlen = x.length();
int ylen = y.length(); int b[X + ][Y + ]; int lcs_max_len = Lcs_Length( x, y, b, xlen,ylen );
cout << lcs_max_len << endl; Display_Lcs( xlen, ylen, x, b, lcs_max_len, lcs_max_len );
cout << "共有:" << cnt << "种"; return ;
}

运行结果如下:

BDAB
BCAB
BCBA
共有: 种

/****************************************

    update

****************************************/

示例:

#include <iostream>
using namespace std;
#define X_LEN 7
#define Y_LEN 6
#define EQUAL 0
#define UP 1
#define LEVEL 2
void lcs_length(char* X,char* Y,int c[X_LEN+][Y_LEN+],int b[X_LEN+][Y_LEN+]);
void print_lcs(int b[X_LEN+][Y_LEN+],char *X,int i,int j); int main()
{
char X[X_LEN+] = {' ','A','B','C','B','D','A','B'};
char Y[Y_LEN+] = {' ','B','D','C','A','B','A'};
int c[X_LEN+][Y_LEN+]={};
int b[X_LEN+][Y_LEN+] = {};
int i,j;
lcs_length(X,Y,c,b);
for(i=;i<=X_LEN;i++)
{
for(j=;j<=Y_LEN;j++)
cout<<c[i][j]<<" ";
cout<<endl;
}
cout<<"The length of LCS is: "<<c[X_LEN][Y_LEN]<<endl;
cout<<"The longest common subsequence between X and y is: "<<endl;
print_lcs(b,X,X_LEN,Y_LEN);
return ;
}
//采用动态规划方法自底向上的进行计算,寻找最优解
void lcs_length(char* X,char* Y,int c[X_LEN+][Y_LEN+],int b[X_LEN+][Y_LEN+])
{
int i,j;
//设置边界条件,即i=0或者j=0
for(i=;i<X_LEN;i++)
c[i][] = ;
for(j=;j<Y_LEN;j++)
c[][j] = ;
for(i=;i<=X_LEN;i++)
for(j=;j<=Y_LEN;j++)
{
if(X[i] == Y[j]) //满足递归公式第二条
{
c[i][j] = c[i-][j-]+;
b[i][j] = EQUAL ;
}
else if(c[i-][j] >= c[i][j-]) //递归公式第三条
{
c[i][j] = c[i-][j];
b[i][j] = UP;
}
else
{
c[i][j] = c[i][j-];
b[i][j] = LEVEL;
}
}
}
void print_lcs(int b[X_LEN+][Y_LEN+],char *X,int i,int j)
{
if(i== || j==)
return;
if(b[i][j] == EQUAL)
{
print_lcs(b,X,i-,j-);
cout<<X[i]<<" ";
}
else
if(b[i][j] == UP)
print_lcs(b,X,i-,j);
else
print_lcs(b,X,i,j-);
}

结果:

Algorithm --> 最长公共子序列(LCS)的更多相关文章

  1. 编程算法 - 最长公共子序列(LCS) 代码(C)

    最长公共子序列(LCS) 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定两个字符串s,t, 求出这两个字符串最长的公共子序列的长度. 字符 ...

  2. POJ 1458 Common Subsequence(最长公共子序列LCS)

    POJ1458 Common Subsequence(最长公共子序列LCS) http://poj.org/problem?id=1458 题意: 给你两个字符串, 要你求出两个字符串的最长公共子序列 ...

  3. 51nod 1006:最长公共子序列Lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  4. 1006 最长公共子序列Lcs

    1006 最长公共子序列Lcs 基准时间限制:1 秒 空间限制:131072 KB 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdks ...

  5. 动态规划之最长公共子序列LCS(Longest Common Subsequence)

    一.问题描述 由于最长公共子序列LCS是一个比较经典的问题,主要是采用动态规划(DP)算法去实现,理论方面的讲述也非常详尽,本文重点是程序的实现部分,所以理论方面的解释主要看这篇博客:http://b ...

  6. C++版 - Lintcode 77-Longest Common Subsequence最长公共子序列(LCS) - 题解

    版权声明:本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C++版 - L ...

  7. 51Nod 1006:最长公共子序列Lcs(打印LCS)

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  8. 51nod 1006 最长公共子序列Lcs 【LCS/打印path】

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

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

    最长公共子序列(LCS) 思路: 代码: def LCS(string1,string2): len1 = len(string1) len2 = len(string2) res = [[0 for ...

随机推荐

  1. freemarker报错之十四

    1.错误描述 <html> <head> <meta http-equiv="content-type" content="text/htm ...

  2. CSS3的[att$=val]选择器

    1.实例源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...

  3. Linux系统安装软件出错

    root@youhaidong-Edge-E545:/home/youhaidong# apt-get install install_flash_player_11_linux.x86_64.tar ...

  4. 芝麻HTTP:在阿里云上测试Gerapy教程

    1.配置环境 阿里云的版本是2.7.5,所以用pyenv新安装了一个3.6.4的环境,安装后使用pyenv global 3.6.4即可使用3.6.4的环境,我个人比较喜欢这样,切换自如,互不影响. ...

  5. java实现马踏棋盘问题

    1.问题描述: 在国际象棋中,马走日,用户输入棋盘的起始位置从x:0-4,y:0-3输出从这一点开始,马走完整个棋盘的各个方案,并输出方案数 2.输入样式: 请输入棋盘马起始位置: 0 0 3.输出样 ...

  6. ASP.NET 后台打开新页面

    [TOC] Response.Write 这是最常见的后台打开新页面的方法. Response.Write("<script>window.open('~/FileView.as ...

  7. Python基础__字符串拼接、格式化输出与复制

    上一节介绍了序列的一些基本操作类型,这一节针对字符串的拼接.格式化输出以及复制的等做做详细介绍.一. 字符串的拼接 a = 'I', b = 'love', c = 'Python'. 我们的目的是: ...

  8. H5 EventSource 实现web页面推送功能demo

    /** * H5 EventSource 实现web页面推送功能demo */ var serverData,statusDiv; var SERVER_URL = "index.php&q ...

  9. [BZOJ1005] [HNOI2008] 明明的烦恼 (prufer编码)

    Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N ...

  10. 【bzoj2820】GCD

    Time Limit: 3000 ms Memory Limit: 256 MB description ​ 神犇GJS虐完数论后给zzHGR出了一个数论题. ​ 给定n,m,求1≤x≤n,1≤y≤m ...