动态规划——最长公共子序列

这篇具有很好参考价值的文章主要介绍了动态规划——最长公共子序列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先来讲解以下什么是最长公共子序列。最长公共子序列不是最长相同字符串,有点相似但不一样,来举个简单的例子,有字符串s1=bcdea,s2=abce,最长相同字符串是bc,最大公共部分是2;而最长公共子序列则是bce,最大公共部分是3。可以看出,公共子序列不需要连续相等,有相同的序列即可。

明白了概念之后,我们来看一下题目。


2-1 两个字符串的所有最长公共子序列 (转自PTA)

求两个字符串的所有最长公共子序列。

输入格式:

输入长度≤100的两个字符串。

输出格式:

输出两个字符串的所有最长公共子序列,若最长公共子序列多于1个,则将所有子序列按字典序从小到大排序后输出。

输入样例1:

ABCBDAB
BDCABA

输出样例1:

BCAB
BCBA
BDAB

输入样例2:

ABACDEF
PGHIK

输出样例2:

NO

读完题目之后还有点懵的话,那就先听一下我的思路。本题要输出的是最长公共子序列,可能的情况可以分为三种:不存在、只有一条和有多条。如果我们逐个去枚举的话,如果遇到存在多条的情况,是很容易出错并且漏选。那我们可以先求出其最长的长度是多少,再用回溯法,一一找出。

求最大公共子序列的长度

string s1, s2;
int arr[101][101]={0};//动态规划表
set <string> lsc_s;
int lsc_max(int m, int n)//求出最大公共子序列的长度 
{
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(s1[i-1]==s2[j-1])arr[i][j]=arr[i-1][j-1]+1;
			else arr[i][j]=max(arr[i-1][j],arr[i][j-1]);
		}
	}
	return arr[m][n];
}

s1、s2是要输入的两个字符串,set是集合(后面再讲)。我们怎么来比较呢,设立一个二维表,即上面的arr,字符串s1为纵列,字符串s2为横行。

动态规划——最长公共子序列

首先拿出s1中的第一个字符和s2中逐一比较,可得出b行b列的意思是s1中b和s2中ab比较,有1个公共的,故为1;b行c列是s1中b和s2中abc比较,也只有一个公共,也为1;再举一个例子,e行e列是s1中bcde和s2中abce比较,因为e和e相同,并且前面s1中bcd和s2中abc比较时已经有两个公共的了,所以要2+1=3;以此类推,可得出此表,同时我们也可以得出一条递推公式,即

if s1[i]==s2[j],arr[i][j]=arr[i-1][j-1]+1;

else arr[i][j]=max{ arr[i][j-1], arr[i-1][j] };

即可得出最长公共子序列的最大长度arr[i][j]。下一步就可根据回溯法来获取公共子序列的所有序列并打印。

打印所有最长公共子序列

void lsc_print(int i, int j, string str)
{
	while(i>0&&j>0)
	{
		if(s1[i-1]==s2[j-1])
		{
			i--;
			j--;
			str=s1[i]+str;
		}
		else
		{
			if(arr[i-1][j]>arr[i][j-1])i--;
			else if(arr[i-1][j]<arr[i][j-1])j--;
			else 
			{
				lsc_print(i-1,j,str);
				lsc_print(i,j-1,str);
				return;
			}
		}
	}
	if(str.length())lsc_s.insert(str);
}

从arr[i][j]开始回溯,当s1[i-1]==s2[j-1]时,说明此公共子序列中包括这个元素,即可把这个元素加入到临时变量str中(头插法),因为是回溯,满足条件的元素在前面;当s1[i-1]!=s2[j-1]时,说明arr[i][j]是由arr[i-1][j]或者arr[i][j-1]继承而来,所以可以判断这两个哪个比较大,就跑去那边,当两边一样大的时候,说明可能存在不同的最长子序列,所以可以进行递归分别求解。当回溯完成后,把str放入到set容器中储存起(为什么用set不用数组,因为题目要求按字典序从小到大输出,set底层是红黑树,自动帮我们排列好,感兴趣的同学可以去看看set用法和底层操作)。

最终ac代码如下:

#include<iostream>
#include<string>
#include<set>
using namespace std;
string s1, s2;
int arr[101][101]={0};//动态规划表
set <string> lsc_s;
int lsc_max(int m, int n)//求出最大公共子序列的长度 
{
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(s1[i-1]==s2[j-1])arr[i][j]=arr[i-1][j-1]+1;
			else arr[i][j]=max(arr[i-1][j],arr[i][j-1]);
		}
	}
	return arr[m][n];
}
void lsc_print(int i, int j, string str)
{
	while(i>0&&j>0)
	{
		if(s1[i-1]==s2[j-1])
		{
			i--;
			j--;
			str=s1[i]+str;
		}
		else
		{
			if(arr[i-1][j]>arr[i][j-1])i--;
			else if(arr[i-1][j]<arr[i][j-1])j--;
			else 
			{
				lsc_print(i-1,j,str);
				lsc_print(i,j-1,str);
				return;
			}
		}
	}
	if(str.length())lsc_s.insert(str);
}
int main()
{
	cin>>s1>>s2;
	int m=s1.length();
	int n=s2.length();
	int len=lsc_max(m,n);
	string str;
	lsc_print(m, n, str);
	set<string>::iterator it=lsc_s.begin();
	if(lsc_s.empty())
	{
		cout<<"NO"<<endl;
		return 0;
	}
	while(it!=lsc_s.end())
	{
		cout<<*it<<endl;
		it++;
	}
	return 0;
}

如果本篇文章对你有所帮助的话,记得点赞哦!如果哪里写得不好的话,也可以评论,欢迎指正!文章来源地址https://www.toymoban.com/news/detail-418204.html

到了这里,关于动态规划——最长公共子序列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划之最长公共子序列模板

    夏令营:动态规划特训 - 【算法模板题】最长公共子序列 - 蓝桥云课 (lanqiao.cn) 我们来解释一下状态转移方程吧。 dp[i][j]的含义是第i个和第j个字符,i与j的下标从1开始,代表着原子符串的第一个字符。那么理所当然字符串a的第0个字符和字符串b的0个字符的公共长度为0.如果字

    2024年02月12日
    浏览(31)
  • 动态规划-----最长公共子序列(及其衍生问题)

    目录 一.最长公共子序列的基本概念: 解决动态规划问题的一般思路(三大步骤): 二.最长公共子序列题目: 三.字符串的删除操作: 四.最小 ASCII 删除和: 首先需要科普一下,最长公共子序列(longest common sequence)和最长公共子串(longest common substring)不是一回事儿。什么

    2024年03月26日
    浏览(34)
  • 【动态规划】最长公共子序列Python实现

    个人主页:丷从心 系列专栏:动态规划算法 问题描述 给定两个序列 X = {   x 1 , x 2 , ⋯   , x m   } X = set{x_{1} , x_{2} , cdots , x_{m}} X = { x 1 ​ , x 2 ​ , ⋯ , x m ​ } 和 Y = {   y 1 , y 2 , ⋯   , y n   } Y = set{y_{1} , y_{2} , cdots , y_{n}} Y = { y 1 ​ , y 2 ​ , ⋯ , y n ​ } ,找出 X X X

    2024年02月20日
    浏览(34)
  • 动态规划-最长公共子序列(c语言)

    实验 3: 最长公共子序列 内容: 给定两个字符串str1和str2,输出两个字符串的最长公共子序列,如果最长公共子序列为空,则返回“-1”。目前给出的数据,仅仅会存在一个最长的公共子序列。 数据范围: 0 ≤|str1|,|str2|≤2000 要求: 空间复杂度O(n 2 ) 具体思路: step1:

    2024年02月04日
    浏览(33)
  • (Java) 算法——动态规划 最长公共子序列 图解

    遇到了用动态规划来求解最长公共子序列问题,算法这块儿比较薄弱,便想着在网上找现成的思路和代码,也算拾人牙慧,但有一点没想到,都已经22年了,关于LCS问题网上给出的答案如此一言难尽……,只有零散几篇对于 新手 来说比较友好,但也仅仅这样,好在自己花了点

    2023年04月08日
    浏览(34)
  • 两个数组的动态规划——最长公共子序列模型

    1.考虑空串,即dp表多出一行一列, 代表某个字符串为空。 2.考虑最后一个位置;是否相等; 3.可在字符串最前面加虚拟位置以对应映射关系; 4.一般横行是j,列是i。此时第一行代表第二个字符串不为空,即第一个字符串是空的 给你两个字符串  s   和  t  ,统计并返回在

    2024年03月10日
    浏览(56)
  • 【动态规划】最长公共子序列——算法设计与分析

    子序列是给定序列中在任意位置去掉任意多个字符后得到的结果。例如: 给定序列 X X X : X : A B C B D A B X:ABCBDAB X : A BCB D A B X X X 的子序列: X 1 : A B C B D A B X_1:ABCBDAB X 1 ​ : A BCB D A B X 2 : A B C B X_2:ABCB X 2 ​ : A BCB X 3 : A C B B X_3:ACBB X 3 ​ : A CBB 给定两个序列

    2024年02月05日
    浏览(37)
  • 动态规划应用篇:详解最长公共子序列问题

    动态规划 是一个强大的工具,将复杂问题 分解 为多个容易解决的子问题,并且会对中间结果进行存储从而避免重复计算,然后将它们的解组合起来,形成大问题的解,高效地得出 全局最优解 。前面我们已经了解了动态规划的基础知识及一维动态规划问题的求解,今天,我

    2024年04月15日
    浏览(34)
  • 【算法(四·三):动态规划思想——最长公共子序列问题】

    最长公共子序列(Longest Common Subsequence,简称LCS)问题是一种常见的字符串处理问题。它的**目标是找到两个或多个字符串中的最长公共子序列,这个子序列不需要是连续的,但字符在原始字符串中的相对顺序必须保持一致。**例如,考虑两个字符串\\\"ABCD\\\"和\\\"ACDF\\\",它们的最长公

    2024年04月13日
    浏览(36)
  • 【算法】力扣【动态规划,LCS】1143. 最长公共子序列

    1143. 最长公共子序列 本文是对 LCS 这一 动态规划 模型的整理,以力扣平台上的算法题1143:最长公共子序列为模板题进行解析。 该题目要求计算两个字符串的最长公共子序列(Longest Common Subsequence,简称LCS)的长度。字符串的子序列是指在不改变字符顺序的情况下,通过删去

    2024年01月17日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包