首页 > 其他分享 >线性dp:最长公共子序列

线性dp:最长公共子序列

时间:2024-08-23 13:48:40浏览次数:9  
标签:-- else 序列 int 公共 线性 最长 dp

最长公共子序列

  • 本文讲解的题与leetcode1143.最长公共子序列这题一样,阅读完可以挑战一下。

力扣题目链接

题目叙述:

给定两个字符串,输出其最长公共子序列,并输出它的长度

输入:

ADABEC和DBDCA

输出:

DBC
3

解释

最长公共子序列是DBC,其长度为3

动态规划思路:

  • 我们这题先构建一个模型,我们使用两个指针i,j ,分别用于遍历a字符串,b字符串。如图所示:

img

  • 然后我们可以设想一个状态变量,也就是一个函数。一个关于两个变量相关的函数,这在代码中体现为二维数组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]是否在当前的最长公共子序列当中。

  • 具体情况如下图:

img

递推公式:

  • f[i][j]可以分为三种情况讨论,就是:
  1. a[i]b[j]都在最长公共子序列当中,也就是a[i]==b[j]
  2. a[i]!=b[j],并且a[i]不在公共子序列当中。
  3. a[i]!=b[j],并且b[j]不在公共子序列当中。
  • 那我们的递推公式就可与分为两种情况:
    • f[i][j]=f[i-1][j-1]+1a[i]==b[j]
    • f[i][j]=max(f[i-1][j],f[i][j-1])a[i]!=b[j]
  • 显而易见,我们的边界条件为:
    • f[0][j]=0
    • f[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的那些元素。
  • 例子如下:

img

  • 我们使用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;
}

标签:--,else,序列,int,公共,线性,最长,dp
From: https://www.cnblogs.com/Tomorrowland/p/18369777

相关文章

  • 线性dp:最长公共子串
    最长公共子串本文讲解的题与leetcode718.最长重复子数组,题意一模一样,阅读完本文以后可以去挑战这题。力扣链接题目叙述:给定两个字符串,输出其最长公共子串的长度。输入ABACCBAACCAB输出3解释最长公共子串是ACC,其长度为3。与最长公共子序列的区别公共子串:字符必须......
  • 线性代数
    看了很多题目,个人觉得现阶段以考察矩阵乘法(快速幂)、高斯消元法求线性方程组的解、矩阵优化dp、一些trick(线段树维护矩阵,kmp套矩阵等)以及矩阵自身性质的深层次运用为主。P1962斐波那契数列应该是典题。从这道题我们可以发现矩阵优化dp的最有效办法是手模,所以此类题目一般......
  • dp
    前情提要dp专题复习树形dp其实对我来说树形dp会比序列dp学得好一些,因为树是有一个具体形态的东西,推式子是比较具象的。其实序列就是把树拍平在数轴上去dp的,只要考虑到这一点,画出dp的转移图,式子就可以呼之欲出了。不套路的dp考验人类智慧的时刻到了!P1352没有上司......
  • python socket编辑示例 UDP
    服务端:fromsocketimportsocket,AF_INET,SOCK_DGRAMrecv_socket=socket(AF_INET,SOCK_DGRAM)recv_socket.bind(('127.0.0.1',8888))whileTrue:data,addr=recv_socket.recvfrom(1024)#接收数据print('客户说:',data.decode('......
  • 4-线性回归
    python中*运算符的使用用于将可迭代对象(如列表或元组)的元素解压缩为单独的参数当我们从Dataloader取出来的时候,又会将压缩为的单独参数分开importtorchfromtorch.utilsimportdata#准备数据true_w=torch.tensor([2,-3.4])true_b=4.2defsynthetic_data(w,b......
  • Little Bird(单调队列优化的DP)
    题目描述有一排\(n\)棵树,第\(i\)棵树的高度是\(d_i\)。有一只鸟要从第\(1\)棵树飞到第\(n\)棵树。如果鸟降落在第\(i\)棵树,那么它下一步可以降落到第\(i+1,i+2,\dots,i+k\)棵树之中的一棵。如果鸟降落到一棵不矮于当前树的树,那么它的劳累值会\(+1\),否则不会。求劳累值的最小值......
  • 线性回归(Linear Regression)
    一、损失(Loss)类型:L1损失【Re】:对模型对各个样本的预测的绝对误差求和。平均绝对误差(MAE)【Re】:一组样本L1损失的平均值。L2损失:【Re】对模型【Re】对各个样本的预测的误差的平方求和。均方误差【Re】:一组样本的L2 损失的平均值。如果数据中特征值超过了一定范围,或者模......
  • 计数DP
    闲话NFLS。话说AT计数dp好题挺多啊。[ABC248F]KeepConnect题解区已经讲得十分清楚了。套路地搞dp,将连通载入其中。\(dp_{i,j,0/1}\)表示前\(i\)列,断了\(j\)条边,上下是否连通的方案数。这里我们保证所有的点都与第\(i\)列其中的\(1\)或两个点相连。然后就可以转......
  • 网络通信(TCP+UDP通信)
    一、UDP协议 1.1、recvfrom()参数说明intsockfd,//socket的fdvoid*buf,//保存数据的一块空间的地址size_tlen,//这块空间的大小intflags,//0默认的接收方式-----阻塞方式默认行为是阻塞a.MSG_DONTWAIT不阻塞方式,用他的话代表读的时候是非阻塞方式b.类似......
  • C# start thread include Thread,Task,Async/Await,BackgroundWorker,ThreadPool,Time
    usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Text;usingSystem.Threading;usingSystem.Threading.Tasks;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Data;using......