最长公共子序列(LCS)
来源:互联网 发布:数控机床编程步骤 编辑:程序博客网 时间:2024/06/11 10:50
定义:
最长公共子序列,英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。而最长公共子串(要求连续)和最长公共子序列是不同的
例如 下面两个单词中颜色标记出来的 data 就是 didactical 和 advantage 的 最长公共子序列, 长度为4;didactical
advantage
求解:
一、首先我们用递归思想设计一个正确、可行的解。
①如果其中一个序列为空,那么最长公共子序列一定为空,长度为 0 。
②我们比较这两个序列的最后一个字母,如果相同,我们就可以将可以将问题规模缩小1位。
例如:
apple appl
abstpdple 最后一个相同 , 我们就可以进而求 abstpdpl 的最长公共子序列, 当然这时候要记录下已经有了的公共部分。
③如果最后一位不同怎么办?
例如
ap
abstpd , 可以想到 ,这时候问题分为了两个部分:
a ap
求解 abstpd 的最长公共子序列 ,和 abstpd 的最长公共子序列
因为最后一个字符不一样,所以我们必定要舍弃两个序列中其中一个的最后一位。显然,我们需要这两个问题中公共子序列更长的那一个。
这样,整个递归算法就算描述完了。
实现的代码在文章最后给出,最好自己直接按照上述描述敲出来代码。
二、寻找优化:动态规划的思想。
我们可以简单的对上面递归的算法进行一些时间分析
最好的情况,也就是不出现③中情况的时候,只需要O(min(lena,lenb)).
然而一旦出现③,那么问题就会分解为两个问题,更糟糕的是,这两个问题的子问题可能雷同!
如图可以看到,两个子问题的子问题可能雷同,将造成大量的重复计算。
最坏的情况将达到 C(lena,lena+lenb)(组合数符号), 当lena == lenb 时 ,大致为 O(2^n)。
时间复杂度达到了指数级别!
这里我们运用动态规划的思想,刚才递归是自顶向下,我们自底向上的去求解问题。
首先初始化dp数组的第一行和第一列为0;
如图所示,我们可以一行一行的填写这张表,运用上面递归中所讲的方法,
如果遇到相同的字符,dp[i][j] = dp[i-1][j-1] + 1 ,
如果遇到不同的字符 dp[i][j] =max(dp[i-1][j] , dp[i][j-1]) .
这样每个空格只用遍历一次就能求出所有的结果,dp[lena][lenb]就是结果啦。
源代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn = 600;int dp[maxn][maxn];//递归版本的LCSint fun(string a,string b,int count){int lena = a.length();int lenb = b.length();if(lena == 0 || lenb == 0)return count;string tmpa,tmpb;tmpa = a.substr(0,lena-1);tmpb = b.substr(0,lenb-1);if(a[lena-1] == b[lenb-1]){return fun(tmpa,tmpb,count+1);}else {return max(fun(tmpa,b,count),fun(a,tmpb,count));}}//动态规划LCSvoid dynamic(string a,string b){int lena = a.length();int lenb = b.length();for(int i=0;i<=lena;i++){dp[i][0] = 0;}for(int i=0;i<=lenb;i++){dp[0][i] = 0;}for(int i=0;i<lena;i++){for(int j=0;j<lenb;j++){if(a[i] == b[j]){dp[i+1][j+1] = dp[i][j] + 1;}else{dp[i+1][j+1] = max(dp[i+1][j] , dp[i][j+1]);}}}printf("%d\n",dp[lena][lenb]);}void print(){//打印dp数组for(int i=0;i<=lena;i++){for(int j=0;j<=lenb;j++){printf("%d ",dp[i][j]);}puts("");}}int main(){string a,b;while(getline(cin,a)){getline(cin,b);dynamic(a,b); //动态规划// int ans = fun(a,b,0); //递归版本// printf("%d\n",ans);}return 0;}
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)问题
- 最长公共子序列(LCS)问题
- 求最长公共子序列(LCS)
- 最长公共子序列算法(LCS)
- LCS(最长公共子序列)
- 最长公共子序列(LCS)问题
- 最长公共子序列(LCS问题)
- Coincidence(LCS最长公共子序列)
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)问题
- 最长公共子序列(LCS)问题
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)
- hdu1243 最长公共子序列(LCS)
- 最长公共子序列(LCS)
- 最长公共子序列(LCS)问题
- Eclipse开发环境搭建
- PL/SQL database character set(AL32UTF8) and Client character set(ZHS16GBK) are different
- 黑马程序员——异常处理全过程:不怕一万,就怕万一
- 预读、物理读、逻辑读
- 【Jenkins系列之三】在Windows上安装Jenkins master & slave
- 最长公共子序列(LCS)
- HDU-5455 Fang Fang(2015沈阳网赛,带坑点水题)
- lucene的使用详解
- xcode7,ios9 部分兼容设置
- 同一Activity实例被多次重复创建的解决方法
- Sending redirect to another servlet/JSP without loosing the request parameters
- Android 音频录制(Audio Capture)
- 检查iOS项目中是否使用了IDFA
- IP,子网掩码,默认网关和DNS都是什么,有什么用