最长上升子序列问题

本文介绍了如何使用动态规划解决最长上升子序列问题,包括不连续情况的线性dp算法,并探讨了连续情况下快速判断的方法。还涉及二维最长递增子序列(信封嵌套问题)的贪心策略。

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

 1.最长上升子序列

1.不连续的情况

最长上升子序列作为线性dp的模板题

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int s[1005];
int dp[1005];
/*最长上升子序列
* 本题的dp思路是:第i个元素构成一个单调子序列时它前面的元素可能是来自前面任意一个元素
* 或者前面没有一个元素是比他小的,他自己本身作为一个序列,长度是1
* 那么我们要考虑两个情况:1.它本身是(1~i)中最小的元素时候 他的值是1
*						  2.它本身比前面的一个元素小时,他的值就是这个元素目前的序列长度+1
*	我们要遍历N个元素 
	我们要遍历第i个元素的前i-1个元素 ---》二重循环
* 
*/
int pre[1000];
int main()
{
	int N;
	cin >> N;
	for (int i = 1;i <= N;i++)
		cin >> s[i];
	dp[1] = 1;
	for(int i=1;i<=N;i++)
		for (int j = 1;j <= i;j++)
		{
			if (i == j && dp[i] == 0)
				dp[i] = 1;						//如果前面为空,就设置他的子序列为一
			if (s[j] < s[i])
			{
				dp[i] = max(dp[j] + 1, dp[i]);	//保证递增性
				pre[i] = j;						//保存轨迹
			}
		}
	
	int ans = -1;
	for (int i = 1;i <= N;i++)
		ans = max(ans, dp[i]);
	cout << ans;
}

 2.连续的情况

    连续的情况比较好分析,就是在一个给定的序列中,比较前后是不是符合(前一个<后一个)即可,如果不符合的话,就直接断开,符合的话让下标存储值+1

#include <iostream>
#include <algorithm>
using namespace std;
/*本题分析的是连续的情况,时间复杂度O(n)*/
int a[1005];
int dp[1005];
int main()
{
	int n;
	cin >> n;
	for (int i = 1;i <= n;i++)
		cin >> a[i];
	dp[1] = 1;
	int ans = -1;
	for (int i = 2;i <= n;i++)
	{
		if (a[i - 1] < a[i])
		{
			dp[i] = dp[i - 1] + 1;

		}
		else
			dp[i] = 1;
		ans = max(ans, dp[i]);
	}
	cout << ans;
}

3.二维最长递增子序列(信封嵌套问题) 

一定数量的信封,带有整数对 (w, h) 分别代表信封宽度和高度。一个信封的宽高均大于另一个信封时可以放下另一个信封。
求最大的信封嵌套层数。

样例
样例 1:

输入:[[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:
最大的信封嵌套层数是 3 ([2,3] => [5,4] => [6,7])。

 二维的递增子序列问题可以先按照某种顺序排序,排序完之后再根据贪心的策略找到最大的嵌套层数。所以二维的递增子序列问题本质上是一种贪心问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值