最长公共子序列长度和输出(史上注释最全,最完整动态规划方法的代码)(二级指针用法,在调用前开辟空间)

本文介绍如何求解两个字符串的最长公共子序列问题,采用动态规划方法,详细解释了函数功能,并提供了两种不同的代码实现,包括使用二级指针和使用vector的情况。示例展示了具体的运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给定两个字符串str1和str2,输出连个字符串的最长公共子序列。如过最长公共子序列为空,则输出-1。

输入描述:
输出包括两行,第一行代表字符串str1,第二行代表str2。\left( 1\leq length(str1),length(str2) \leq 5000\right)(1≤length(str1),length(str2)≤5000)

输出描述:
输出一行,代表他们最长公共子序列。如果公共子序列的长度为空,则输出-1。
示例1
输入
1A2C3D4B56
B1D23CA45B6A
输出
123456
说明
"123456"和“12C4B6”都是最长公共子序列,任意输出一个。

函数说明

此次方法选择动态规划的方法;
用代码和以下两张图对照看,可以更加清楚:

以下两张图来源于:(关于思路可以参考以下链接文章,代码可以参考本文)

https://blog.youkuaiyun.com/ggdhs/article/details/90713154?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1

如果有两个字符串如下:
S1 = “123456778”
S2 = “357486782”
其最终的动态规划填表结果为:
在这里插入图片描述
在这里插入图片描述

/***************************************************
统计公共子串长度,并将完成标签数组的记录。
s1,s2输入的字符串,len记录最长公共子串的长度
tag标签数组指向一个二维数组,标记字符串中哪个字符被选做为最长公共子序列中的一个
****************************************************/

void LCS(string s1, string s2,int &len,int **tag);

/***********************************************
找到公共子序列,并记录在res中
利用标签数组tag的记录来输出公共子序列
tag中:0代表选择这个元素,1代表可能选择同列前一行的元素,- 1代表可能选择同行前一列的元素
s1输入的字符串(s2也行);
i,j代表寻找到标签数组的行列号;
res代表输出的公共子序列
************************************************/

void Print(string s1, int i, int j, string& res, int** tag);

代码

#include<iostream>
#include<string>
#include<vector>
using namespace std;

/***************************************************
统计公共子串长度,并将完成标签数组的记录。
s1,s2输入的字符串,len记录最长公共子串的长度
tag标签数组指向一个二维数组,标记字符串中哪个字符被选做为最长公共子序列中的一个
****************************************************/
void LCS(string s1, string s2,int &len,int **tag);

/***********************************************
找到公共子序列,并记录在res中
利用标签数组tag的记录来输出公共子序列
tag中:0代表选择这个元素,1代表可能选择同列前一行的元素,- 1代表可能选择同行前一列的元素
s1输入的字符串(s2也行);
i,j代表寻找到标签数组的行列号;
res代表输出的公共子序列
************************************************/
void Print(string s1, int i, int j, string& res, int** tag);

void main() {
	int i = 0, j = 0;
	string s1 , s2;
	int len=0;//最长公共子序列长度
	string res;//记录最长公共子序列
	//cin >> s1 >> s2;
	s1 = "1A2C3D4B56";
	s2 = "B1D23CA45B6A";

	//对标签数组开辟空间。
	int** tag = new int*[s1.size() + 1];//指向一个二维数组,标记字符串中哪个字符被选做为最长公共子序列中的一个
	for(int i=0;i<s1.size()+1;++i)
	tag[i] =new int[s2.size()+1];
	memset(tag, 0, sizeof(tag));//初始化0

	LCS(s1, s2, len,tag);
	Print( s1,s1.size(), s2.size(),res,tag);
	cout <<len<<" "<< res << endl;
	
	//对标签数组进行释放内存
	for (int i = 0; i < s1.size() + 1; ++i)
		delete[]tag[i];
	delete[]tag;

}
void LCS(string s1, string s2, int& len, int **tag) {
	int m = s1.size();
	int n = s2.size();
	vector<vector<int>>tmp(m+1, vector<int>(n+1, 0));
	for (int i = 1; i <= m; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (s1[i - 1] == s2[j - 1]) {
				tmp[i][j] = tmp[i - 1][j - 1] + 1;
				tag[i][j] = 0;
			}
			else {
				if (tmp[i - 1][j] >= tmp[i][j - 1])
					tmp[i][j] = tmp[i - 1][j], tag[i][j] = 1;
				else
					tmp[i][j] = tmp[i][j - 1], tag[i][j] = -1;
			}
		}
	}
	len = tmp[m][n];
}
//tag 0代表选择这个元素,1代表选择同列前一行的元素,-1代表选择同行前一列的元素
void Print(string s1,int i,int j, string& res, int **tag) {
	if (i == 0 || j == 0)
		return;
	if (tag[i][j] == 0) {
		//res += s1[i - 1];//这样是顺着输出
		Print( s1,i - 1, j - 1, res,tag);
		res += s1[i - 1];//这样是倒着输出,递归时从后往前输出,倒倒得顺
	}
	else if (tag[i][j] == 1) 
		Print(s1, i - 1, j ,res,tag);
	else
		Print(s1, i , j - 1,res,tag);
}

在这里插入图片描述

当对tag不想用二级指针,用vector时代码如下:

#include<iostream>
#include<string>
#include<vector>
using namespace std;

/***************************************************
统计公共子串长度,并将完成标签数组的记录。
s1,s2输入的字符串,len记录最长公共子串的长度
tag标签数组指向一个二维数组,标记字符串中哪个字符被选做为最长公共子序列中的一个
****************************************************/
void LCS(string s1, string s2, int& len, vector<vector<int>>& tag);

/***********************************************
找到公共子序列,并记录在res中
利用标签数组tag的记录来输出公共子序列
tag中:0代表选择这个元素,1代表可能选择同列前一行的元素,- 1代表可能选择同行前一列的元素
s1输入的字符串(s2也行);
i,j代表寻找到标签数组的行列号;
res代表输出的公共子序列
************************************************/
void Print(string s1, int i, int j, string& res, vector<vector<int>>& tag);

void main() {
	int i = 0, j = 0;
	string s1, s2;
	int len = 0;//最长公共子序列长度
	string res;//记录最长公共子序列
	//cin >> s1 >> s2;
	s1 = "1A2C3D4B56";
	s2 = "B1D23CA45B6A";
	vector<vector<int>>tag(s1.size() + 1, vector<int>(s2.size() + 1, 0));

	LCS(s1, s2, len, tag);
	Print(s1, s1.size(), s2.size(), res, tag);
	cout << len << " " << res << endl;
}
void LCS(string s1, string s2, int& len, vector<vector<int>>& tag) {
	int m = s1.size();
	int n = s2.size();
	vector<vector<int>>tmp(m + 1, vector<int>(n + 1, 0));
	for (int i = 1; i <= m; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (s1[i - 1] == s2[j - 1]) {
				tmp[i][j] = tmp[i - 1][j - 1] + 1;
				tag[i][j] = 0;
			}
			else {
				if (tmp[i - 1][j] >= tmp[i][j - 1])
					tmp[i][j] = tmp[i - 1][j], tag[i][j] = 1;
				else
					tmp[i][j] = tmp[i][j - 1], tag[i][j] = -1;
			}
		}
	}
	len = tmp[m][n];
}
//tag 0代表选择这个元素,1代表选择同列前一行的元素,-1代表选择同行前一列的元素
void Print(string s1, int i, int j, string& res, vector<vector<int>>& tag) {
	if (i == 0 || j == 0)
		return;
	if (tag[i][j] == 0) {
		//res += s1[i - 1];//这样是顺着输出
		Print(s1, i - 1, j - 1, res, tag);
		res += s1[i - 1];//这样是倒着输出,递归时从后往前输出,倒倒得顺
	}
	else if (tag[i][j] == 1)
		Print(s1, i - 1, j, res, tag);
	else
		Print(s1, i, j - 1, res, tag);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力做一个code杠精

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值