最长上升子序列II(贪心)

题目:

给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。

数据范围:

N<100010

-10^9<=序列中的数<=10^9

分析

q[i]表示长度是i的上升子序列最后一个数的最小值q[]的长度就是最大可能的上升子序列长度

q[r + 1] = a[i]:这里并没有选择最小的而直接等于a[i]是因为可以保证“相等长度的上升序列,后来得到的序列的结尾数值一定小于或等于前面得到的”,假设先前得到的序列xxxa,后来得到的序列xxxb,a和b满足b在a的后面且b>a,那么显然xxxb一定不是以b结尾的最长上升子序列,正确序列中一定包含a,所以假设不成立,命题得证。

数据示例(来源于acwing)

输入:

7

3 1 2 1 8 5 6

执行过程:

  • i=0, l=0, r=len=0 不满足二分条件 ——> len=r+1=1,q[1]=a[0]=3
  • i=1, l=0, r=len=1 进行二分 ——> r=0, len=1,q[1]=a[1]=1
  • i=2, l=0, r=len=2 进行二分 ——> r=1, len=2,q[2]=a[2]=2
  • i=3, l=0, r=len=2 进行二分 ——> r=0, len=2,q[1]=a[3]=1
  • i=4, l=0, r=len=2 进行二分 ——> r=2, len=3,q[3]=a[4]=8
  • i=5, l=0, r=len=3 进行二分 ——> r=2, len=3,q[3]=a[5]=5
  • i=6, l=0, r=len=3 进行二分 ——> r=3, len=4,q[4]=a[6]=6

结果为   4

代码

#include<iostream>
#include<iostream>

using namespace std;

const int N=100010;
int n;
int a[N];	//存储每个数
int q[N];	//存储不同长度下所有上升子序列结尾的最小值 

int main()
{
	scanf("%d",&n); 	
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	
	int len=0;		//q里面的元素个数
	for(int i=0;i<n;i++)	//枚举一下每个数 
	{
		//需要二分出来小于某个数的最大的数 -- 如何二分? 
		//可以二分的原因,不同长度的最后一个数是严格单调递增的 
		int l=0,r=len;
		while(l<r)
		{
			//这个二分是找右端点 
			int mid = l+r+1>>1;
			if(q[mid]<a[i]) l=mid; 
			else r=mid-1; 
		}
		len = max(len,r+1);
		q[r+1] = a[i];
	}
	
	cout<<len;
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值