LCS(最长公共子序列)
这个问题很有意思,在生物应用中,经常需要比较两个(或多个)不同生物体的DNA片段。例如,某种生物的DNA可能为S1 = ACCGGTCGAGTGCGCGGAAGCCGGCCGAA,S2 = GTCGTTCGGAATGCCGTTGCTCTGTAAA。比较两个DNA串是想要确定它们之间的“相识度”,作为度量两种生物相近程度的指标。LCS就是寻找第三个串S3,S3满足定义:给定一个序列X = <x1,x2,...,xn>,另一个序列Y = <y1,y2,...,ym>即存在一个严格递增的X的下标序列<i1,i2,...,im>,对所有j = 1,2,...,m,满足xij = zj。例如,Z = BCDB是ABCBDAB的子序列,对应的下标为[2,3,5,7]。
如果用暴力求解则很容易就达到指数阶的运行时间,所以显然需要优化。通过分析发现LCS问题具有最优子结构性质,于是,考虑用动态规划是一个非常不错的方案。
显然早就有许多人对此类问题做过很多工作,不管是理论上还是实际测试,都证明动态规划可以解决这一类型的问题,有时候甚至是最优方案。如何熟练使用动态规划的一大难点在于分析问题,要理解如何使用动态规划来解决问题,首先分析问题是否具有最优子结构是重要的,然后就是通过分析问题得到递归公式,只要得到了递归公式,我们就可以使用动态规划了。
LCS问题也不例外,经过分析和查资料,我们知道了LCS得最优子结构定理:
令X = <x1,x2,...,xn>和Y = <y1,y2,...ym>为两个序列,Z = <z1,z2,...,zk>为X和Y的任意LCS。
- 如果xn = ym,则zk = xn = ym且Zk - 1是Xn - 1和Ym - 1的一个LCS;
- 如果xn ≠ ym且zk ≠ xn,说明Z是Xn - 1和Y的一个LCS;
- 如果xn ≠ ym且zk ≠ ym,说明Z是X和Ym的一个LCS;
然后,我们开始建立最优解的递归式。定义dp[i][j]为Xi和Yj的LCS长度。显然的,当i = 0或j = 0时,LCS = 0。再结合最优子结构定理,可得到递归式:
- ( 0; 当 i = 0 或 j = 0;
- dp[i][j] = { dp[i - 1][j - 1] + 1 当 i,j > 0 且 xi = yj;
- ( max(dp[i][j - 1], dp[i - 1][j]) 当 i,j > 0 且 xi != yj.
得到递归式后,就可以根据公式写出递归算法或动态规划算法:
- #include <iostream>
- #include <string>
- #include <vector>
- #include <minmax.h>
- class Solution {
- public:
- int LongestCommonSubsequence(std::string s1, std::string s2) {
- if (s1.empty() || s2.empty())
- return 0;
- std::vector<std::vector<int> > dp(s1.size(), std::vector<int>(s2.size(), 0));
- int length = 0;
- for (int i = 1; i < dp.size(); i++) {
- for (int j = 1; j < dp[0].size(); j++) {
- if (s1[i] == s2[j])
- dp[i][j] = dp[i - 1][j - 1] + 1;
- else
- dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
- length = max(length, dp[i][j]);
- }
- }
- return length + 1;
- }
- };
- int main()
- {
- Solution solve;
- std::string s1{"ABCBDAB"};
- std::string s2{"ABDCABA"};
- std::cout << solve.LongestCommonSubsequence(s1, s2) << std::endl;
- return 0;
- }
最后,类似的问题还有LIS(最长递增子序列)、LPS(最长回文子串)等等。
参考资料:
《算法导论》
LCS(最长公共子序列)的更多相关文章
- 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列
出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...
- POJ 1458 Common Subsequence(LCS最长公共子序列)
POJ 1458 Common Subsequence(LCS最长公共子序列)解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?c ...
- 动态规划模板2|LCS最长公共子序列
LCS最长公共子序列 模板代码: #include <iostream> #include <string.h> #include <string> using n ...
- LCS 最长公共子序列
区别最长公共子串(连续) ''' LCS 最长公共子序列 ''' def LCS_len(x, y): m = len(x) n = len(y) dp = [[0] * (n + 1) for i ...
- LCS最长公共子序列(最优线性时间O(n))
这篇日志主要为了记录这几天的学习成果. 最长公共子序列根据要不要求子序列连续分两种情况. 只考虑两个串的情况,假设两个串长度均为n. 一,子序列不要求连续. (1)动态规划(O(n*n)) (转自:h ...
- LCS最长公共子序列
问题:最长公共子序列不要求所求得的字符串在所给字符串中是连续的,如输入两个字符串ABCBDAB和BDCABA,字符串BCBA和BDAB都是他们的公共最长子序列 该问题属于动态规划问题 解答:设序列X= ...
- LCS最长公共子序列HDU1159
最近一直在学习算法,基本上都是在学习动态规划以及字符串.当然,两者交集最经典之一则是LCS问题. 首先LCS的问题基本上就是在字符串a,b之间找到最长的公共子序列,比如 YAOLONGBLOG 和 Y ...
- POJ 2250(LCS最长公共子序列)
compromise Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Descri ...
- LCS最长公共子序列~dp学习~4
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 Palindrome Time Limit: 4000/2000 MS (Java/Others ...
- Atcoder F - LCS (DP-最长公共子序列,输出字符串)
F - LCS Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement You are gi ...
随机推荐
- 被女朋友三番五次拉黑后,我用 Python 写了个“舔狗”必备神器
在一个阳光明媚的周日,我打开窗户呼吸了一口新鲜空气.阳光灿烂,岁月静好,又是一个约女朋友出去爬山吃饭看电影的好日子. 想到女朋友的大眼睛,我脸上不禁洋溢起了幸福的微笑.打开微信,给女朋友发出去一个美好 ...
- 读书笔记 - 把时间当作朋友 by 李笑来
要管理的不是时间,而是自己. 摸着石头渐行渐远,最终也能过河.- 朱敏 赛伯乐(中国)投资公司 董事长 一切都靠积累,一切都可提前准备,越早醒悟越好.人的一生是奋斗的一生,但是有的人一生过得很伟大,有 ...
- The Preliminary Contest for ICPC Asia Xuzhou 2019 M. Longest subsequence(思维+序列自动机)
序列自动机跑s串 假设k为s和t相同的长度,初始时相同长度为0 取s串中大于t[i]的最左边的位置,用n-tmp+1+i-1更新答案,tmp是最左端的位置 然后去t[i]相等的位置,走到下一位,如果下 ...
- c++写入注册表
一.说明: 注册表是Windows重要组成部分,注册表记录了大量有关电脑软硬件的信息.注册表中的值通过其名称标识.值名称由与键名相同的字符组成.值本身可以是字符串.二进制数据或者是32位无符 ...
- Educational Codeforces Round 75 (Rated for Div. 2)D(二分)
#define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;pair<int,int>a[20 ...
- 正则去掉 html标签
var htmlStr='<p class="cjk" style="margin-bottom: 0cm; line-height: 16px;"> ...
- Codeforces Round #576 (Div. 2) 题解
比赛链接:https://codeforc.es/contest/1199 A. City Day 题意:给出一个数列,和俩个整数\(x,y\),要求找到序号最靠前的数字\(d\),使得\(d\)满足 ...
- 【Go语言系列】1.3、GO语言简介:Go语言开发的知名项目
下面列举的是原生使用Go语言进行开发的部分项目.1.DockerDocker 是一种操作系统层面的虚拟化技术,可以在操作系统和应用程序之间进行隔离,也可以称之为容器.Docker 可以在一台物理服务器 ...
- python3实现在二叉树中找出和为某一值的所有路径
在二叉树中找出和为某一值的所有路径请写一个程序创建一棵二叉树,并按照一定规则,输出二叉树根节点到叶子节点的路径.规则如下:1.从最顶端的根结点,到最下面的叶子节点,计算路径通过的所有节点的和,如果与设 ...
- Spring学习(九)
JdbcTemplate需要的jar包 1.Spring核心必须依赖的库:commons-logging-1.1.1.jar2.Spring IoC部分核心库: spring-beans-4.3.9. ...