Longest Ordered Subsequence
时间复杂度为O(nlogn)的二分查找计算最长上升子序列的算法:
定义c数组:c[i]记录长度为i的上升子序列的结尾的值,其结尾值越小,意味着其潜能越大,越有可能被后来的数接上,所以每一个数扫一遍,利用二分法寻找恰好比它小的c数组的i值,更新一遍c数组,最后输出c数组的最长长度
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1010;
int n,len;
int a[maxn],c[maxn];
int bs_search(int l,int r,int key)
{
if(l==r)return l;
int mid=(l+r)>>1;
if(c[mid]<key) return bs_search(mid+1,r,key);
else return bs_search(l,mid,key);
}
int main()
{
int tmp;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
c[0]=-INF;
for(int i=1;i<=n;i++)
{
if(a[i]>c[len]) tmp=++len;
else tmp=bs_search(0,len,a[i]);
c[tmp]=a[i];
}
printf("%d",len);
}
另外二分查找可以利用 C++ STL中已有的lower_bound函数,其返回的是c数组中数的地址
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1010;
int n,len;
int a[maxn],c[maxn];
int main()
{
int tmp;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
c[0]=-INF;
for(int i=1;i<=n;i++)
{
if(a[i]>c[len]) tmp=++len;
else tmp=lower_bound(c+1,c+len+1,a[i])-c;
c[tmp]=a[i];
}
printf("%d",len);
}