最长上升子序列

描述

一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1a2, ..., aN),我们可以得到一些上升的子序列(ai1ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

输入

输入的第一行是序列的长度N。第二行给出序列中的N个整数。

输出

最长上升子序列的长度。

总结了四种方法:枚举O(2^n) ,动态规划O(n^2) ,数组维护+二分O(nlogn) ,线段树O(nlogn)

枚举code:

#include<bits/stdc++.h>
using namespace std;
int n,a[15],ans=0;
int s(int x,int l){
	if(x==n) return 0;
	if(a[x]>l) return max(s(x+1,a[x])+1,s(x+1,l));
	return s(x+1,l);
}
int main() {
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<n-1;i++){
		ans=max(ans,s(i+1,a[i])+1);
	}
	cout<<ans<<endl;
	return 0;
} 

动态规划code:

include<bits/stdc++.h>
using namespace std;
int n,a[1010],f[1010],ans;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];f[i]=1;
	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);
		}
		ans=max(ans,f[i]);
	}
	cout<<ans<<endl;
	return 0;
}

数组维护code:

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn=3e5+10;
int a[maxn],lst[maxn],f[maxn],n;
int main(){
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	int ans=0;
	for(int i=1;i<=n;i++){
		f[i]=lower_bound(lst+1,lst+1+ans,a[i])-lst;
		lst[f[i]]=a[i];
		ans=max(ans,f[i]);
	}
	cout<<ans<<endl;
	return 0;
}

线段树code:

#include<bits/stdc++.h>
#define endl '\n'
#define gcd __gcd
#define lson (p<<1)
#define rson (p<<1|1)
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
struct T{
	int l,r,mx;
}t[maxn<<2];
void build(int p,int l,int r){
	t[p].l=l,t[p].r=r,t[p].mx=0;
	if(l==r) return;
	int mid=l+r>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
}
void change(int p,int x,int val){
	if(t[p].l==t[p].r){
		//cout<<t[p].l<<' '<<x<<endl;
		t[p].mx=max(t[p].mx,val);
		return;
	}
	int mid=t[p].l+t[p].r>>1;
	if(x<=mid) change(lson,x,val);
	if(x>mid) change(rson,x,val);
	t[p].mx=max(t[lson].mx,t[rson].mx);
}
int query(int p,int l,int r){
	if(l>r) return 0;
	if(l<=t[p].l&&t[p].r<=r) return t[p].mx;
	int mx=0,mid=t[p].l+t[p].r>>1;
	if(mid>=l) mx=max(mx,query(lson,l,r));
	if(r>=mid+1) mx=max(mx,query(rson,l,r));
	return mx;
}
int n,a[maxn],v[maxn],ans;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],v[i]=a[i];
	build(1,1,n);
	sort(v+1,v+1+n);
	int m=unique(v+1,v+1+n)-v-1;
	for(int i=1;i<=n;i++){
		int x=lower_bound(v+1,v+1+m,a[i])-v;
		int num=query(1,1,x-1)+1;
		change(1,x,num);
		ans=max(ans,num);
		//cout<<query(1,1,1)<<endl;
	}
	//cout<<query(1,1,1)<<endl;
	cout<<ans<<endl;
	return 0;	
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值