《编程之美》第2.16节:求数组中最长递增子序列
问题:写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度。
解法:可以暴力求解,复杂度为O(N^2),另外可以开辟一个数组maxV,其中maxV[i]存放长度为i的递增子序列最大的元素的最小值,用二分法搜索maxV元素,从而使复杂度能够降到O(NlogN)。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
int lowerBinarySearch(int A[],int N,int val)
{
int lo=0,hi=N;
while(lo<hi)
{
int mid=(lo+hi)/2;
if(A[mid]>=val)
hi=mid;
else
lo=mid+1;
}
return A[lo]>=val?lo-1:lo;
}
int longestIncreaseSubarray(int *A,int N)
{
if(N<=1)
return N;
int *maxV=new int[N+1];
maxV[1]=A[0];
maxV[0]=INT_MIN;
int *lis=new int[N];
for(int i=0;i<N;i++)
lis[i]=1;
int nMaxLis=1;
for(int i=1;i<N;i++)
{
int j;
j=lowerBinarySearch(maxV,nMaxLis,A[i]);
lis[i]=j+1;
if(lis[i]>nMaxLis)
{
nMaxLis=lis[i];
maxV[lis[i]]=A[i];
}
else if(maxV[j]<A[i] && A[i]<maxV[j+1])
maxV[j+1]=A[i];
}
return nMaxLis;
}
int longestIncreaseSubarrayNN(int *A,int N)
{
if(N<=1)
return N;
int *lis=new int[N];
for(int i=0;i<N;i++)
{
lis[i]=1;
for(int j=0;j<i;j++)
{
if(A[j]<A[i] && lis[j]+1>lis[i])
lis[i]=lis[j]+1;
}
}
int result=0;
for(int i=0;i<N;i++)
if(lis[i]>result)
result=lis[i];
return result;
}
int main()
{
const int N=10000;
int A[N]={};
generate(A,A+N,rand);
int result=longestIncreaseSubarray(A,N);
int resultNN=longestIncreaseSubarrayNN(A,N);
cout<<result<<endl;
cout<<resultNN<<endl;
system("pause");
return 0;
}
为了验证算法的有效性,这里将暴力算法结果也同时输出了,这样能够对比说明算法的正确性。