【难】求数组中最长递增子序列,时间复杂度O(nlogn)

来源:互联网 发布:赛道狂飙 国家永恒mac 编辑:程序博客网 时间:2024/05/16 06:49

题目:《编程之美》 P194

写一个时间复杂度尽可能低的程序,求一个数组(length个元素)中最长递增子序列的长度。

注意,本题认为最长递增子序列可以有相等的元素,如 (1,2,2,3,3,4,5,6)。


时间复杂度为O(n^2)的程序思路很简单,参考书上的解法一。针对O(n^2)的解法进行改进,利用有序数组的二分查找,可以使得时间复杂度降低。本题的难点在于,建立一个长度为length+1的数组MinV,MinV[i]代表着长度为i的递增子序列最大元素的最小值。而且数组MinV是升序的,理解这一点尤其关键。

以下是时间复杂度为O(nlogn)的代码:

//在有序数组MinV中,从下标1到endindex的部分,寻找小于等于k的数中最大的那个数,返回其下标//若所有数都大于k,返回-1int Find_Less_Than_K(const int* MinV,const int endindex,const int k){int left=1,right=endindex,res=-1;while(left<=right){int mid=left+(right-left)/2;if(MinV[mid]<=k){res=mid;left=mid+1;}elseright=mid-1;}return res;}int longest_increasing_subsequence(const int* arr,const int length){if(arr==nullptr || length<=0)return -1;int* LIS=new int[length];int* MinV=new int[length+1];for(int i=0;i<length;i++){LIS[i]=1;MinV[i]=INT_MAX;}MinV[length]=INT_MAX;MinV[1]=arr[0];int res=1,endindex=1;for(int i=1;i<length;i++){int index=Find_Less_Than_K(MinV,endindex,arr[i]);if(index!=-1){LIS[i]=index+1;if(LIS[i]>res){res=LIS[i];endindex=res;}}if(arr[i]<MinV[LIS[i]])MinV[LIS[i]]=arr[i];}delete[] MinV;delete[] LIS;return res;}


0 0
原创粉丝点击