最长升序子序列

最长升序子序列

有两种算法,算法的时间复杂度分别是O(n^2)和O(nlogn)
O(n^2)
dp[i] 指从0~i的最大子升序
但此时的最大值并不一定时最长升序子序列

#include <stdio.h>
#include <iostream>
using namespace std;
int a[100005];
int dp[100005];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 0;i < n;i++){
		scanf("%d",a+i);
		int maxn = 0;
		//求升序在a[i]的值,
		//那么a[j]肯定要小于a[i]
		//找到a[j] < a[i],并且dp[j]最大的值赋值给maxn
		for(int j = 0;j < i;j++){
			if(a[j] < a[i]){//如果是等于,那么就可以相等if(a[j] <= a[i]),这是非降序
				maxn = max(dp[j],maxn);
			}
		}
		//maxn已经是最大并且j<i ,那么加上1就好了 
		dp[i] = maxn+1;
	}
	//为了找到最大值
	maxn = dp[0];
	for(int i = 0;i < n;i++){
		maxn = max(dp[i],maxn);
	}
	printf("%d\n",maxn);
	return 0;
}

O(nlogn)
定义一个数组f,设数组的元素为len
如果此时的x>f[len-1] ,那么就把x添加到数组f的末尾中,并且数组f的个数+1
如果小于那么就在数组f中从开始往后遍历,替换第一个大于等于x的,因为是上升,所以相邻两个不能相等
比如
f[10000] = {1,2,3,10,13,}
x = 10
,此时的x应该是替换f数组中的10,而不是13
所以就就应该用lower_bound,所以是找到第一个大于等于x的下标
结果就是len

#include <stdio.h>
#include <algorithm>
using namespace std;
int f[300005];
int main()
{
	int n;
	int len = 0;
	while(~scanf("%d",&n)){
		len = 0;
		for(int i = 0;i < n;i++){
			int x;
			scanf("%d",&x);
			if(len == 0) f[len++] = x;
			else if(x>f[len-1]) f[len++] = x;
			else {
				int k = lower_bound(f,f+len,x)-f;
				f[k] = x;
			}
		} 
		printf("%d\n",len);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42868863/article/details/89449746