最长上升子序列 O(n^2)和O(nlogn)

最长上升子序列 
【题目描述】
给定N个数,求这N个数的最长上升子序列的长度。
【样例输入】
7
2 5 3 4 1 7 6
【样例输出】

4

注:在网上看了不少关于最长上升子序列的求解方法 总结能力不太好 只能举例子了 

方法一
用b[i]表示以a[i]结尾的上升子序列的长度 时间复杂度为O(n^2)
#include<bits/stdc++.h>
using namespace std;
void init(int * b,int N)
{
	for(int i=0;i<N;i++){
		b[i] = 1;
	}
}
int main()
{
	int N,i,j,a[1000],max=0;
	int b[1000];//用来记录 以a[i]结尾的上升子序列的长度
	cin>>N;
	for(i=0;i<N;i++){
		cin>>a[i];
	} 
	init(b,N);//把b数组初始化为1 当a[i]前面的元素都比a[i]大时 b[i] = 1; 
	for(i=1;i<N;i++){
		for(j=0;j<i;j++){
			if(a[i]>a[j]){//首先要保证0~i-1有比a[i]小的 要不然b[i]为不更新,值为1 
				if(b[j]+1 > b[i]){//其次保证更新b[i]的值有意义 
					b[i] = b[j] +1;//可以a[i] = 7 a[j] = 1时为例 此时就不能更新b[i]的值 
				}
			}
		}
		if(b[i]>max){//寻找最长的 
			max = b[i];
		}
	}
	cout<<max; 
	return 0;	
} 

方法二 
b[len] 代表 所有长度为len的上升子序列中最末位元素得最小值 
例如
2 5 3 4 1 7 6
a[1] = 2 时 b[1] = 2 目前长度为1 最小的为2 b[1] = 2 
a[2] = 5 时 b[2] = 5 5>b[1] 长度+1 b[2] = 5
a[3] = 3 时 b[2] = 3 3<b[2] 数组b中的某个值要更新 
a[4] = 4 时 b[3] = 4 4>b[2]  b[2+1] = 4 
a[5] = 1 时 b[1] = 1 1<b[3] 更新 
a[6] = 7 时 b[4] = 7 7>b[3] b[3+1] = 7 
a[7] = 6 时 b[4] = 6 6<b[4] 更新 (以6为结尾的上升子序列长度为k 则b[k] = 6)
综上 : 若 a[i] < b[len](因为b是单调递增所以肯定存在某个元素值要被更新) 
那么在 b[1]~b[len] 中 找到 满足 b[k-1]< a[i]<=b[k] (因为数组可能重复) 
令b[k] = a[i]; 
在查找K这个下标的时候用二分查找 时间复杂度O(nlogn)

#include<bits/stdc++.h>
using namespace std;
int Find(int tmp,int * b ,int Left,int Right);
int main()
{
	int N,i,j,k,a[1000];
	int b[1000],len = 1;
	cin>>N;
	for(i=0;i<N;i++){
		cin>>a[i];
	}
	b[len] = a[0];
	for(i=1;i<N;i++){
		if(a[i]>b[len]){
			b[++len] = a[i];
		}
		else{
			k = Find(a[i],b,1,len);
			b[k] = a[i];
		}
	}
	cout<<len<<endl;
	return 0;	
} 

int Find(int tmp,int * b ,int Left,int Right)
{
	int mid;
	while(Left<=Right){
		mid = (Left + Right)/2;
		if(tmp>b[mid-1] && tmp <=b[mid]){
			return mid;
		}
		else if(tmp > b[mid]){
			Left = mid + 1;	
		}
		else{
			Right = mid -1;
		}
	}
} 












猜你喜欢

转载自blog.csdn.net/qq_39562286/article/details/79678314