dp最长公共子序列详细版本(LCS)

本文介绍了最长公共子序列(LCS)的概念,通过一个B站博主的视频讲解,详细阐述了如何使用动态规划求解LCS。文章提供了解题思路,包括状态设计和状态转移方程,并给出了两段C++代码,分别用于计算两个字符串的LCS长度和输出LCS序列。以字符串'algorithm'和'alchemist'为例,展示了LCS为'alhms',长度为5。

最长公共子序列,这是 B站 一个博主的讲解视频,讲的很好,看完这个视频你接下来甚至可以不看我这篇博客,但如果你觉得视频太长,欢迎继续往下看看我从视频里提取的精华内容。

目录

1、定义

2、常规题目

3、解题思路

 4、解题代码

5、扩展


1、定义

最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。
上面的解释是百度给出的,我再用白话解释一下,其实也就是给出几个不同的字符串(一般是两个),然后求它们的公共子序列,可以不连续。举个例子,字符串algorithmsalchemist(为了方便观察,LCS我用红色加粗表示)的LCS即alhms。

2、常规题目

描述:

给定两个序列s1、s2,求二则的公共子序列长度。

输入:

第一行输入第一个序列

第二行输入第二个序列

输出:

输出一个数字,即两个序列的公共子序列长度。

3、解题思路

主要还是用到动态规划,但要理清楚其中的意思。

① 设计状态

设 f[i][j] 是序列 si={x1,x2,...,xi} 和序列 sj={y1,y2,...,yj}  的公共子序列长度。

② 状态转移方程

现在 i、j 对应三种不同的方程

f[i][j] = 0  -->  i=0或者j=0,si和sj中任意一个序列长度为零,那么它们的 LCS长度就只能为零

f[i][j] = f[i-1][j-1] + 1 --> xi=yj,两个序列的最后一各字符相等,说明长度至少要加一,加一后直接剪掉这个字符,再继续对照 i-1 和 j-1对应的字符,依次对照

f[i][j] =max(f[i-1][j],f[i][j-1])--> xi!=yj,这个用例子说明,假设求abcd和acde的LCS长度,字符 d!=e,现在有两种选择,要么求 abcd 和 acd 的LCS,要么求 abc和 acde 的LCS,但既然是求最长LCS,那么选择两种方案的最大值即可。

 4、解题代码

// 求最长公共子序列 -- dp 
#include <bits/stdc++.h>
using namespace std;
char s1[100],s2[100];
int f[100][100];
int main()
{
	int n,m,i,j;
	gets(s1);
	gets(s2);
	n=strlen(s1),m=strlen(s2);
	// 状态转移方程一 --> f[100][100]本来全都为零,不用管 
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(s1[i-1]==s2[j-1])  f[i][j]=f[i-1][j-1]+1;  // 方程二
			else   f[i][j]=max(f[i-1][j],f[i][j-1]);   // 方程三 
		}
	} 
	cout<<f[n][m]; 
	return 0;
}
/*案例 
algorithms
alchemist
结果: 5 
*/ 

 

5、扩展

上面代码求出的只是LCS的长度,现在我们尝试直接求出这个序列,而不是长度。

// 求最长公共子序列 -- dp 
#include <bits/stdc++.h>
using namespace std;
char s1[100],s2[100];
int f[100][100];
void LCS(int i,int j)
{
	if(i==0||j==0)  return ;  //回溯 
	if(s1[i-1]==s2[j-1])
	{
		LCS(i-1,j-1);  //递归
		cout<<s1[i-1]; 
	}
	else if(f[i-1][j]>f[i][j-1])
	{
		LCS(i-1,j);
	}
	else
	{
		LCS(i,j-1);
	} 
} 
int main()
{
	int n,m,i,j;
	gets(s1);
	gets(s2);
	n=strlen(s1),m=strlen(s2);
	// 状态转移方程一 --> f[100][100]本来全都为零,不用管 
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(s1[i-1]==s2[j-1])  f[i][j]=f[i-1][j-1]+1;  // 方程二
			else   f[i][j]=max(f[i-1][j],f[i][j-1]);   // 方程三 
		}
	} 
	cout<<f[n][m]<<endl;    // 序列长度 
	LCS(n,m);  //  求序列  函数 
	return 0;
}
/*案例 
algorithms
alchemist
结果: 
5 
alhms
*/ 

结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值