最长公共上升子序列

本文介绍了如何求解最长公共上升子序列问题,首先讲解了最长上升子序列和最长公共子序列的基本概念及算法实现,并在此基础上融合两者,提出了求解最长公共上升子序列的方法。

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

要求最长公共上升子序列(LCIS),我们要先学会最长上升子序列(LIS)和最长公共子序列(LCS)。

最长上升子序列

求数列aaa的最长上升子序列
fif_ifi表示前iii个数的最长上升子序列的长度,则fi=max⁡j<i∧a[j]<a[i]fjf_i=\max\limits_{j< i\wedge a[j]<a[i]}f_jfi=j<ia[j]<a[i]maxfj

code

for(int i=1;i<=n;i++){
	for(int j=1;j<i;j++){
		if(a[i]>a[j]) f[i]=max(f[i],f[j]+1);
	}
}

这个代码是O(n2)O(n^2)O(n2)的,用线段树或树状数组可以优化到O(nlogn)O(nlogn)O(nlogn),但这与我们的主题没有太大关联,所以这里就不再赘述了。

最长公共子序列

求数列aaa和数列bbb的最长公共子序列
fi,jf_{i,j}fi,j表示数列aaaiii个和数列bbbjjj个的最长公共子序列,则fi,j=max(fi,j−1,fi−1,j,fi−1,j−1+(ai==bj))f_{i,j}=max(f_{i,j-1},f_{i-1,j},f_{i-1,j-1}+(a_i==b_j))fi,j=max(fi,j1,fi1,j,fi1,j1+(ai==bj))

code

for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		f[i][j]=max(f[i-1][j],f[i][j-1]);
		if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
	}
}

时间复杂度也是O(n2)O(n^2)O(n2)

最长公共上升子序列

求最长公共上升子序列就是前两种方法的结合。
fi,jf_{i,j}fi,j表示数列aaaiii个和数列bbbjjj个的最长公共子序列。当ai==bja_i==b_jai==bj时,在[i,j−1][i,j-1][i,j1]中选出最大的fi,kf_{i,k}fi,k并转移

for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		f[i][j]=[i-1][j];
		if(a[i]==b[j]){
			int mx=1;
			for(int k=1;k<j;k++){
				if(a[i]>b[k]) mx=max(mx,f[i-1][k]+1);
			}
			f[i][j]=max(f[i][j],mx);
		}
	}
}

时间复杂度为O(n3)O(n^3)O(n3),很容易时超,所以我们要稍微优化一下
每次求mxmxmx是在[1,j−1][1,j-1][1,j1]中求最大值,而jjj是从小到大增加的,那么我们可以在jjj增大的时候顺便求出此时mxmxmx的值,就可以省去一维循环,还能将fff数组压掉一维。

code

for(int i=1;i<=n;i++){
	int mx=1;
	for(int j=1;j<=m;j++){
		if(a[i]==b[j]){
			f[j]=max(f[j],mx);
		}
		if(a[i]>b[j]){
			mx=max(mx,f[j]+1);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值