线性dp:最长公共子序列
最长公共子序列
- 本文讲解的题与leetcode1143.最长公共子序列这题一样,阅读完可以挑战一下。
题目叙述:
给定两个字符串,输出其最长公共子序列,并输出它的长度
输入:
ADABEC和DBDCA
输出:
DBC
3
解释
最长公共子序列是DBC,其长度为3
动态规划思路:
- 我们这题先构建一个模型,我们使用两个指针
i,j,分别用于遍历a字符串,b字符串。如图所示:

然后我们可以设想一个状态变量,也就是一个函数。一个关于两个变量相关的函数,这在代码中体现为二维数组
f。然后
f[i][j]表示什么呢?表示序列a[1,2,3....i]和b[1,2,3....j]的最长公共子序列的长度
状态变量的含义
在这里的状态变量为
f[i][j],它的含义是a的前i个字符与b的前j个字符的最长公共子序列的长度现在就要观察
a[i],b[j]是否在当前的最长公共子序列当中。具体情况如下图:

递推公式:
f[i][j]可以分为三种情况讨论,就是:
a[i],b[j]都在最长公共子序列当中,也就是a[i]==b[j]a[i]!=b[j],并且a[i]不在公共子序列当中。a[i]!=b[j],并且b[j]不在公共子序列当中。
- 那我们的递推公式就可与分为两种情况:
f[i][j]=f[i-1][j-1]+1(a[i]==b[j])f[i][j]=max(f[i-1][j],f[i][j-1])(a[i]!=b[j])
- 显而易见,我们的边界条件为:
f[0][j]=0f[i][0]=0
//m是a字符串的长度,n是b字符串的长度
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
//因为我们的f数组是从下标1开始,而字符串是从0开始的下标
if(a[i-1]==b[j-1]) f[i][j]=f[i-1][j-1]+1;
else f[i][j]=max(f[i-1][j],f[i][j-1]);
}
}
遍历顺序
- 经过上面的分析,明显遍历顺序为
i从小到大,j也是从小到大。
初始化
- 初始化边界为0即可
举例打印dp数组
- 如图所示

如何找出对应的最长公共子序列的长度
我们使用p数组来记录每一次
f[i][j]的值来源于哪一个方向- 1方向代表左上方
- 2方向代表左方
- 3方向代表上方
代码改造如下:
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(a[i-1]==b[j-1]){
f[i][j]=f[i-1][j-1]+1;
//左上方
p[i][j]=1;
}
else if(f[i-1][j]>f[i][j-1]){
f[i][j]=f[i][j-1];
//左边
p[i][j]=2;
}
else{
f[i][j]=f[i-1][j];
//上边
p[i][j]=3;
}
}
}
p[i][j]代表前驱的位置。
算法的执行过程
- 我们要找到最长公共子序列,只需要找到从结尾开始,往前找到
p[i][j]==1,也就是来源于左上方的哪些元素的集合,就是我们的最长公共子序列。(并不是棋盘中所有p[i][j]==1)的元素,而是从右下角出发,往回找到的所有p[i][j]==1的那些元素。 - 例子如下:

我们使用
s数组来储存最长公共子序列代码实现:
int i,j,k;
char s[200];
i=m;j=n;k=f[m][n];
while(i>0&&j>0){
//左上方
if(p[i][j]==1){
s[k--]=a[i-1];
i--;j--;
}
//左边
else if(p[i][j]==2) j--;
//上边
else i--;
}
for(int i=1;i<=f[m][n];i++) cout<<s[i];
最终代码实现:
#include <iostream>
#include <cstring>
using namespace std;
char a[200];
char b[200];
int f[205][205];
int p[205][205];
int m, n;
void LCS() {
int i, j;
m = strlen(a);
n = strlen(b);
for (i = 1; i <= m; i++) {
for (j = 1; j <= n; j++) {
if (a[i - 1] == b[j - 1]) {
f[i][j] = f[i - 1][j - 1] + 1;
p[i][j] = 1;
}
else if (f[i - 1][j] > f[i][j - 1]) {
f[i][j] = f[i - 1][j];
p[i][j] = 2;
}
else {
f[i][j] = f[i][j - 1];
p[i][j] = 3;
}
}
}
cout << f[m][n] << endl;
}
//寻找出当初的最长公共子序列。
void getLCS() {
int i = m, j = n, k = f[m][n];
char s[200];
s[k] = '\0';
while (i > 0 && j > 0) {
if (p[i][j] == 1) {
s[--k] = a[i - 1];
i--; j--;
}
else if (p[i][j] == 2) {
i--;
}
else {
j--;
}
}
cout << s << endl;
}
int main() {
cin >> a >> b;
LCS();
getLCS();
return 0;
}
线性dp:最长公共子序列的更多相关文章
- hdu1159 dp(最长公共子序列)
题意:给两个字符串,求这两个字符串的最长公共子序列的长度 因为之前集训的时候做过,所以现在即使会做也并不是什么稀奇的事,依旧为了自己的浅薄感到羞愧啊``` 解法就是通过两个字符串的每个字符互相比较,根 ...
- POJ 1159 Palindrome(区间DP/最长公共子序列+滚动数组)
Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 56150 Accepted: 19398 Desc ...
- poj1159--Palindrome(dp:最长公共子序列变形 + 滚动数组)
Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 53414 Accepted: 18449 Desc ...
- 经典dp 最长公共子序列
首先,说明一下子序列的定义…… 一个序列A={a1,a2,a3,...,an},从中删除任意若干项,剩余的序列叫A的一个子序列. 很明显(并不明显……),子序列……并不需要元素是连续的……(一开始的时 ...
- HDU 1159 Common Subsequence【dp+最长公共子序列】
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- POJ - 1458 Common Subsequence DP最长公共子序列(LCS)
Common Subsequence A subsequence of a given sequence is the given sequence with some elements (possi ...
- hdu 1503:Advanced Fruits(动态规划 DP & 最长公共子序列(LCS)问题升级版)
Advanced Fruits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...
- POJ1458 Common Subsequence —— DP 最长公共子序列(LCS)
题目链接:http://poj.org/problem?id=1458 Common Subsequence Time Limit: 1000MS Memory Limit: 10000K Tot ...
- 51nod 1183 编辑距离【线性dp+类似最长公共子序列】
1183 编辑距离 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个 ...
- 1. 线性DP 1143. 最长公共子序列
最经典双串: 1143. 最长公共子序列 (LCS) https://leetcode-cn.com/problems/longest-common-subsequence/submissions/ ...
随机推荐
- ubuntu 安装 github desktop
原文: https://gist.github.com/berkorbay/6feda478a00b0432d13f1fc0a50467f1 sudo wget https://github.com/ ...
- 【ClickHouse】0:clickhouse学习1之数据引擎(数据库引擎,表引擎)
ClickHouse提供了大量的数据引擎,分为数据库引擎.表引擎,根据数据特点及使用场景选择合适的引擎至关重要,这里根据资料做一些总结. 数据库引擎官方文档: https://clickhouse.t ...
- 网络化的控制系统简介(NCS)
作为一个搞物联网应用的,最近才接触到NCS这个概念.有点东西,赶紧记录一下. NCS由通过网络连通的控制环路组成,控制信号和反馈信号会在控制器和本地系统间交换.典型的方块图如下: 其中,本地(Plan ...
- 随机数据下 Sqrt Tree 的平替实现
原理 在随机数据下,把原序列分成 \(\sqrt n\) 个块,维护每个块的前缀后缀最大值,那么,在随机询问下,对于在一个块中的询问,暴力查询. 复杂度 概率 $ n ^ {-\frac{1}{2}} ...
- 你真的了解Java内存模型JMM吗?
哈喽,大家好,我是世杰. 本文我为大家介绍面试官经常考察的「Java内存模型JMM相关内容」 面试连环call 什么是Java内存模型(JMM)? 为什么需要JMM? Java线程的工作内存和主内存各 ...
- 洛谷P1004
洛谷P1004方格取数 题目大意 本题简要意思就是一个人从一个数字矩阵的左上角走到右下角,只能向下和向右走,拿完的数对应位置变成0,并且这个人要走两次,需要计算两次所拿数的最大值 Train of t ...
- TP3.2与TP5.0的区别
1. 控制器输出return $this->fetch(); ----5$this->display(); ----3.2单字母函数去掉了 如:M() D() U() S() C() 3. ...
- oeasy教您玩转vim - 31 - # 文字区块
文字区块 回忆上节课内容 上上次讲的翻页 上次先让屏幕位置固定,移动光标 H- Head 移动到屏幕的顶端 M- Middle 移动到屏幕的中间 L- Low 移动到屏幕的底部 然后让光标固定,移 ...
- LLM并行训练6-激活优化
前置知识 Activation 激活指的是一些在fp时计算得到的临时tensor, 会用于bp时的计算. 如果能在fp计算后把临时tensor缓存下来就可以加速bp, 缺点在于某些激活会占用大量显存. ...
- 关于使用UE5打包Android的测试
UE5打包Android,不同于UE4,在官方文档中需要Android studio 4.0或者3.5,还有Android SDK,NDK等 设置SetupAndroid, 在UE5 Editor配置 ...