动态规划---例题2.最长公共子序列问题
本题与力扣主站1143题相同.
一.问题描述
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
确切地说,若给定序列X=<x1, x2,…, xm>,则另一序列Z=<z1, z2,…, zk>是X的子序列是指存在一个严格递增的下标序列 <i1, i2,…, ik>,使得对于所有j=1,2,…,k有
例如,序列Z=<B,C,D,B>是序列X=<A,B,C,B,D,A,B>的子序列,相应的递增下标序列为<2, 3, 5, 7>。
给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
例: X=<A, B, C, B, D, A, B>
Y=<B, D, C, A, B, A>
Z1=<B, C, A>
Z2= <B, C, B, A>
Z1和Z2是X和Y的一个公共子序列,而且Z2是X和Y的一个最长公共子序列,因为X和Y没有长度大于4的公共子序列。(不唯一!)
最长公共子序列(LCS)问题:给定两个序列X=<x1, x2, …, xm>和Y=<y1, y2, … , yn>,要求找出X和Y的一个最长公共子序列。
二.解题思路
穷举搜索法:对X的每一个子序列,检查它是否也是Y的子序列,并选出最长的公共子序列。X的一个子序列相应于下标序列{1, 2, …, m}的一个子序列,因此,X共有2m个不同子序列,从而穷举搜索法需要指数时间。
下面我们来考虑用动态规划法解最长公共子序列问题.此问题是动态规划的典型应用之一.
1.分析最优解的结构
定理:LCS具有最优子结构
设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:
- 若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的最长公共子序列。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。
证明如下(反证法):
- 已知xm=yn ,假如zk≠xm,则<z1, z2, …, zk ,xm >是X和Y的长度为k十1的公共子序列。
这与Z是X和Y的一个最长公共子序列矛盾。因此,必有zk=xm=yn.Zk-1是Xm-1和Yn-1的一个长度为k-1的公共子序列。若Xm-1和Yn-1有一个长度大于k-1的公共子序列W,则将xm加在其尾部将产生X和Y的一个长度大于k的公共子序列。此为矛盾。
故Zk-1是Xm-1和Yn-1的一个最长公共子序列。 - 已知xm≠yn, zk≠xm ,Z是Xm-1和Y的最长公共子序列。假如Z不是Xm-1和Y的最长公共子序列。
zk≠xmàZ是Xm-1和Y的一个公共子序列. 若Xm-1和Y有一个长度大于k的公共子序列W,则W也是X和Y的一个长度大于k的公共子序列。这与Z是X和Y的一个最长公共子序列矛盾。由此即知Z是Xm-1和Y的一个最长公共子序列。 - 与2类似。
这说明:两个序列的最长公共子序列包含了这两个序列的前缀的最长公共子序列。因此,最长公共子序列问题具有最优子结构性质。
2.建立递归关系
由最长公共子序列问题的最优子结构性质可知,要找出X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列,可按以下方式递归地进行:
- 当xm=yn时,{Xm-1和Yn-1的最长公共子序列}的末尾加上 xm
- 当xm≠yn时,Max{Xm-1和Y的一个最长公共子序列,X和Yn-1的一个最长公共子序列}
由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。
根据子问题的最优值的递归关系,我们用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。其他情况下,可建立递归关系如下:
3.计算最优值
直接利用(2.2)式容易写出一个计算c[i,j]的递归算法,但其计算时间是随输入长度指数增长的。由于在所考虑的子问题空间中,总共只有θ(m*n)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。
- c[i,j]存储Xi与Yj的最长公共子序列的长度,X和Y的最长公共子序列的长度记录于c[m,n]中
- b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的,这在构造最长公共子序列时要用到.
4.构建最长公共子序列
LCS_length产生数组b用于构造序列<x1 …, xm>和<y1, …, yn>的最长公共子序列。
首先从b[m,n]开始,沿着其中的箭头所指的方向在数组b中搜索。
- 当b[i,j]="1"时,表示Xi与Yj的最长公共子序列是由Xi-1与Yj-1的最长公共子序列在尾部加上xi得到的子序列;
- 当b[i,j]="2"时,表示Xi与Yj的最长公共子序列和Xi-1与Yj的最长公共子序列相同;
- 当b[i,j]="3"时,表示Xi与Yj的最长公共子序列和Xi与Yj-1的最长公共子序列相同。
代码如下:
// // 最长公共子序列
#include<bits/stdc++.h>
using namespace std;
const int Size = 1010; //尽量用全局变量
int DP[Size][Size];
int DIR[Size][Size];
int LCS_length(string a, string b)
{int M = a.size();int N = b.size();for(int i=1; i<=M; i++){for(int j=1; j<=N; j++){if(a[i-1] == b[j-1]) {DP[i][j] = DP[i-1][j-1] + 1;DIR[i][j] = 1;}else if(DP[i-1][j] >= DP[i][j-1]){DP[i][j] = DP[i-1][j];DIR[i][j] = 2;}else{DP[i][j] = DP[i][j-1];DIR[i][j] = 3;}}}return DP[M][N];
}
void LCS(string a, int i, int j)
{if(i==0 || j==0) return;if(DIR[i][j] == 1) {LCS(a, i-1, j-1);cout<<a[i-1]; //a[i-1]==b[j-1]}else if(DIR[i][j]==2) LCS(a, i-1, j);else if(DIR[i][j]==3) LCS(a, i, j-1);
}
void LCS2(string a, string b, int i, int j) //算法改进,不使用DIR数组,仅仅依靠DP数组以及a,b两个序列
{if(i==0 || j==0) return;if(a[i-1]==b[j-1]){LCS2(a, b, i-1, j-1);cout<<a[i-1]<<endl;}else if(DP[i-1][j] > DP[i][j-1]) LCS2(a, b, i-1, j);else LCS2(a, b, i, j-1);
}
int main()
{string a, b;cout<<"请输入两个字符串:"<<endl;while(cin>>a>>b && a!="GG"){cout<<"最大公共子序列长度为:"<<LCS_length(a, b)<<endl;// LCS(a, a.size(), b.size());cout<<"最大公共子序列为:";LCS2(a, b, a.size(), b.size());cout<<endl<<"请输入两个字符串:"<<endl;}system("pause");return 0;
}
//www.pgcode.top 版权所有
运行结果:
本篇文章参考我的老师毕方明《算法设计与分析》课件.
欢迎大家访问个人博客—乔治的编程小屋,和我一起为大厂offer努力吧!
动态规划---例题2.最长公共子序列问题相关推荐
- 用动态规划算法实现最长公共子序列问题的算法(java实现)
用动态规划算法实现最长公共子序列问题的算法 public class longestCommonSubsequence {//构造追踪数组rec,记录子问题来源private static Strin ...
- 算法复习——动态规划篇之最长公共子序列问题
算法复习--动态规划篇之最长公共子序列问题 以下内容主要参考中国大学MOOC<算法设计与分析>,墙裂推荐希望入门算法的童鞋学习! 1. 问题背景 子序列:将给定序列中零个或多个元素(如字符 ...
- 动态规划算法解最长公共子序列LCS问题
动态规划算法解LCS问题 作者 July 二零一零年十二月三十一日 本文参考:微软面试100题系列V0.1版第19.56题.算法导论.维基百科. 第一部分.什么是动态规划算法 ok,咱们先来了解下什么 ...
- 动态规划算法---求最长公共子序列
最长公共子序列和最长公共子串区别 最长公共子串(Longest Common Substring)与最长公共子序列(Longest Common Subsequence)的区别: 子串要 ...
- 动态规划_求最长公共子序列LCS
学习动态规划有段时间了,我自己的感觉是看到题解很明白,但是拿到新题就后脑冒汗了,费解!我知道这其实是理解不深的缘故,动态规划是解决一类问题的方法,而不是解决某个问题的解法.今天我试着去感觉一下怎么去思 ...
- 【动态规划】【最长公共子序列】Vijos P1111 小胖的水果
题目链接: https://vijos.org/p/1111 题目大意: 多组数据,给两个字符串s1,s2,求把s1,s2拆开从前往后合并后最短是多少 apple + peach = appleach ...
- 动态规划:求最长公共子序列和最长公共子串
最长公共子序列(LCS): 这同样是一道经典题目,定义就不说了. 为了方便说明,我们用Xi代表{x1,x2,‥xi},用Yj代表{y1,y2,‥yj}.那么,求长度分别为m,n的两个序列X,Y的LCS ...
- 动态规划问题中最长公共子序列---C语言实现
一.前言 如上 二.内容 这个问题有点抽象和复杂,我们可以看一个具体的例子. 上表如下:(我是用程序实现的) 得出公式如下: 然后用C语言实现这个具体问题. #include<stdio.h&g ...
- DP方法(动态规划) 寻找最长公共子序列 LCS问题(c++)
Q:有两个序列x,y.其中x={x1,x2-xm},y={y1,y2-yn}.寻找x与y的最长公共子序列. 注:子序列和子串有区别,字串是连续的,而子序列可间断. 呃(⊙﹏⊙),后面的暂时没时间写了, ...
最新文章
- deepin更新失败_检查更新失败
- T-SQL查询进阶--深入理解子查询
- BZOJ3747: [POI2015]Kinoman
- sharepoint部件webparth关闭找回的方法
- 【MATLAB统计分析与应用100例】案例009:创建一个RandStream类对象,调用其randn方法生成标准正态分布随机数
- 比较经典的java程序_一些经典的java小程序代码,最好能复制后直接使用的 爱问知识人...
- 【阮一峰ES6入门教程学习笔记】letconst
- 一个很不错的远程软件TeamViewer
- 多张图片合成一个mp4的视频
- SAI绘制滑雪者教程
- 图像处理与计算机视觉:基础,经典以及最近发展(转)
- 关于PLC控制系统中电动机过载保护方法的探究
- 实时高速实现改进型中值滤波算法_爱学术_免费下载
- Nginx报upstream timed out错误
- 人生是一场盛大的修行
- C语言-八道题深入理解c指针
- d2lzh_pytorch的安装
- 高承实:做链改项目,想不清楚一定不会成功
- matlab2016a运行svmtrain函数出错
- python中的for循环与切片