对于一个数字序列,请设计一个复杂度为O(nlogn)的算法,返回该序列的最长上升子序列的长度,这里的子序列定义为这样一个序列U1,U2...,其中Ui < Ui+1,且A[Ui] < A[Ui+1]。
给定一个数字序列A及序列的长度n,请返回最长上升子序列的长度。
测试样例:
[2,1,4,3,1,5,6],7
返回:4
采用两个辅助数组dp[],help[],数组长度均为n.max_length表示最长递增子序列的长度。
dp[i]表示必须以A[i]结尾的最长递增子序列的长度,help[i]表示递增子序列长度为i+1的所有序列中结尾最小的值。其中dp[0]=1,help[0]=A[0].遍历数字序列A,更改dp[],help[]的值,若dp[i]>max_length,更新max_length的值。最后返回max_length。因为help[]是排好序的,所以在更新help[]时查找A[i]的位置时采用二分搜索。遍历数组+二分搜索更新,所以时间复杂度是O(nlogn)例子:其中红线部分表示更新过程,当插入A[1]=1时,help[0]为2,比1大,所以更新为help[0]=1;当插入A[2]=4时,help[0]=1,比4小,所以更新help[1]=4.重复至遍历数字序列完成。
![](https://i-blog.csdnimg.cn/blog_migrate/680f7e009a2c9d959e232170cf0fad60.png)
代码:
class AscentSequence {
public:
int findLongest(vector<int> A, int n) {
// write code here
int dp[MAX_SIZE];
int help[MAX_SIZE];
int max_length=0,count=0;
dp[0]=1;help[0]=A[0];
for(int i=1;i<n;i++) //遍历数字序列
{
int right=count,left=0,middle;
while(left<=right){ // 查找A[i]更新help[]时的位置
middle=(left+right)/2;
if(A[i]>=help[middle]){
left=middle+1;
}else{
right=middle-1;
}
}
help[left]=A[i]; //更新help[]的值
if(left>count)
count=left;
dp[i]=left+1; //更新dp[]的值
if(dp[i]>max_length) //更新最长递增子序列的长度
max_length=dp[i];
}
return max_length;
}