两个字符串的最长公共子序列

#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
char a[N],b[M];
int main(int argc,char const* args[] ){
	int n,m;
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	cin>>a>>b;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(a[i-1]==b[j-1]){
				f[i][j]=f[i-1][j-1]+1;
			}else{
				f[i][j]=std::max(f[i-1][j],f[i][j-1]);
			}
		}
	}
	cout<<f[n][m]<<endl;	
	return 0;
}

这段代码的数组f[i][j]表示序列a[0…i-1]和b[0…j-1]的最长公共子序列长度。

对于每个位置 (i, j),根据最后一个元素 a[i-1]和b[j-1],可以分为以下几种情况:

  1. 如果a[i-1]等于b[j-1],那么a[i-1]和b[j-1]一定在最长公共子序列中,此时可以在a[0…i-2]和b[0…j-2]的最长公共子序列的基础上加上 a[i-1](或者b[j-1]),所以有 f[i][j] = f[i-1][j-1] + 1。
  2. 如果a[i-1]不等于b[j-1],那么a[i-1]和b[j-1]不能同时在最长公共子序列中。根据公共子序列的定义,可能出现两种情况:
    1. a[i-1]在最长公共子序列中,但b[j-1]不在,此时可以将b[j-1]从序列b中删除,即比较a[0…i-1]和b[0…j-2]的最长公共子序列,所以有 f[i][j] = f[i][j-1]。
    2. b[j-1]在最长公共子序列中,但a[i-1]不在,此时可以将a[i-1]从序列a中删除,即比较a[0…i-2]和b[0…j-1]的最长公共子序列,所以有 f[i][j] = f[i-1][j]。

综上所述,根据不同的情况,可以使用状态转移方程来计算f[i][j]:
f[i][j] =

  • f[i-1][j-1] + 1,当a[i-1]等于b[j-1];
  • max(f[i-1][j], f[i][j-1]),当a[i-1]不等于b[j-1]。

最后,输出f[n][m],即为两个字符串的最长公共子序列的长度。

#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
int8_t p[N][M];
char a[N],b[M],s[N];
int main(int argc,char const* args[] ){
	int n,m;
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	cin>>a>>b;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(a[i-1]==b[j-1]){
				f[i][j]=f[i-1][j-1]+1;
			}else if(f[i-1][j]>f[i][j-1]){
				f[i][j]=f[i-1][j];
				p[i][j]=1;
			}else{
				f[i][j]=f[i][j-1];
				p[i][j]=-1;
			}
		}
	}
	int i=n,j=m,k=f[n][m];
	cout<<k<<endl;
	while(i>0&&j>0){
		switch(p[i][j]){
			case 0: --i;--j;s[--k]=a[i];break;
			case 1: --i;break;
			default:--j
		}
	}
	cout<<s;
	return 0;
}

这段代码实现了最长公共子序列(Longest Common Subsequence)问题的动态规划算法。给定两个字符串a和b,程序计算出它们的最长公共子序列,并输出该子序列的长度和内容。

具体而言,代码中使用一个二维数组f来存储最长公共子序列的长度,数组p用于回溯构建子序列。f[i][j]表示字符串a的前i个字符和字符串b的前j个字符的最长公共子序列的长度。p[i][j]表示从f[i][j]的值推导出来的最长公共子序列的字符位置关系,其中0表示字符a[i]和b[j]都包含在最长公共子序列中,1表示字符a[i]包含在最长公共子序列中,-1表示字符b[j]包含在最长公共子序列中。

代码通过遍历字符串a和字符串b的每个字符,根据字符的匹配关系更新f和p数组的值。最后,利用p数组回溯构建最长公共子序列,并输出结果。

#include <iostream>
#define len (*b)
using std::cin;
using std::cout;
using std::endl;
constexpr int N=105;
constexpr int M=105;
int f[N][M];
//int8_t p[N][M];
char a[N],b[M],s[N];
int main(int argc,char const* args[] ){
	int n,m;
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	cin>>a>>b;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(a[i-1]==b[j-1]){
				f[i][j]=f[i-1][j-1]+1;
			}else if(f[i-1][j]>f[i][j-1]){
				f[i][j]=f[i-1][j];
//				p[i][j]=1;
			}else{
				f[i][j]=f[i][j-1];
//				p[i][j]=-1;
			}
		}
	}
	int i=n,j=m,k=f[n][m];
	cout<<k<<endl;
	while(i>0&&j>0){
//		switch(p[i][j]){
//			case 0: --i;--j;s[--k]=a[i];break;
//			case 1: --i;break;
//			default:--j;
//		}
		if(a[i-1]==b[j-1]){
			--j;s[--k]=a[--i];
		}else if(f[i-1][j]>f[i][j-1]){
			--i;
		}else{
			--j;
		}
	}
	cout<<s;
	return 0;
}

这段代码实现了最长公共子序列(Longest Common Subsequence)问题的动态规划算法,和前一个版本不同的是这里不再使用p数组来回溯构建最长公共子序列,而是直接利用条件语句。

具体而言,代码中使用一个二维数组f来存储最长公共子序列的长度。f[i][j]表示字符串a的前i个字符和字符串b的前j个字符的最长公共子序列的长度。

程序通过遍历字符串a和字符串b的每个字符,根据字符的匹配关系更新f数组的值。最后,利用条件语句根据当前字符的匹配情况,更新i、j以及s数组的值。最终,输出最长公共子序列的长度和内容。

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

朝闻道 晨星

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

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

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

打赏作者

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

抵扣说明:

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

余额充值