AcWing算法基础课打卡 | 896 最长上升子序列 II

学习C++从娃娃抓起!记录下在AcWing算法基础课中打卡题目,记录每一个瞬间。

附上汇总贴:AcWing算法基础课打卡 | 汇总


【题目描述】

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

【输入】

第一行包含整数 N N N

第二行包含 N N N 个整数,表示完整序列。

【输出】

输出一个整数,表示最大长度。

【输入样例】

7
3 1 2 1 8 5 6

【输出样例】

4

【分析】

本题数据规模是10万,不能用动态规划(数据规模1000左右)

1.贪心策略:

(1)q[i]:上升序列长度为i,最后一个数为q[i],要长度最大,末端应最小值,len上升序列最大长度。

(2)a[i]保证以a[i]结尾的上升序列最长。在q[0]-q[len]找最右的点 A,q[A]<a[i],最长上升序列为…q[A] a[i]。

2.二分查找,上升序列中最后一个比a[i]小的点即分界点A,二分返回r,q[r+1]=a[i],形成以a[i]结尾的新的上升序列。上升序列长len=r+1,len上升序列长度最大值。

在这里插入图片描述

3.样例。初始q[i]=0,上升序列长len = 0

(1)a[1]=3 → r=0,q[0]=0,q[1]=3,len=1

(2)a[2]=1 → r=0,q[0]=0,q[1]=1,len=1

(3)a[3]=2 → r=1,q[0]=0,q[1]=1,q[2]=2,len=2

(4)a[4]=1 → r=0,q[0]=0,q[1]=1,q[2]=2,len=2

(5)a[5]=8 → r=2,q[0]=0,q[1]=1,q[2]=2,q[3]=8,len=3

(6)a[6]=5 → r=2,q[0]=0,q[1]=1,q[2]=2,q[3]=5,len=3

(7)a[7]=6 → r=3,q[0]=0,q[1]=1,q[2]=2,q[3]=5,q[4]=6,len=4

4.len上升序列长度最大值。保证上升序列长度为i,序列末端值最小,最小值存入q[i]:

(1)若q[1]=x;序列中下一个数y,如果y<x,则替换q[1]=y → 长度为1的序列末端值最小。

(2)当y>x时,上升序列长度+1,q[2]=y,则q[1]<q[2] → q[ ]值递增

(3)当前状态q[1]=x,q[2]=y,q[1]<q[2],序列中下一个数z

(4)如果z<x<y,则q[ ]数组中大于z的只有q[0]=0;则q[0+1]=q[1]=z;q[0]<q[1]<q[2] → 长度为1的序列末端值最小,q[ ]值递增

(5)如果z>x>y,则q[ ]数组中q[2]>y,q[3]=z,q[0]<q[1]<q[2]<q[3]

在这里插入图片描述

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int a[N];
int q[N];  //q[i]上升序列长度为i,序列末端最小值为q[i]
int main()
{
	cin >> n;
	for (int i=0; i<n; i++) cin >> a[i];  // 读入序列
	int len = 0;  // 已经求出的最大上升序列长度
	for (int i=0; i<n; i++) {
		int l=0, r=len;
		while (l<r) {
			int mid = (l+r+1)/2;
			if (q[mid]<a[i]) l=mid;
			else r=mid-1;
		}
		q[r+1] = a[i];
		len = max(len, r+1);
	}

	cout << len << endl;
	return 0;
}

【运行结果】

7
3 1 2 1 8 5 6
4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值