最长上升子序列O(nlogn)算法
来源:互联网 发布:最流行的网络语言 编辑:程序博客网 时间:2024/05/19 01:09
上个月参加腾讯校园招聘的笔试,填空部分有一道题问:计算最长上升子序列的最快算法
的时间复杂度和空间复杂度是多少?
例如序列:{1 4 2 3 7 6 5 7}的最长上升子序列是{1 2 3 6 7},长度为5。
此题的答案是O(nlogn)和O(n),在这之前我只了解n^2的算法,没有看过nlogn的算法,到网上搜索
发现对于该算法的介绍都比较晦涩难懂,因此我决定弄懂它后写一篇blog,详细介绍该算法,让他尽量
容易理解。
为了便于描述,假设序列存放在num数组中。
对于该问题,我们很快就能找到一个简单算法。
定义数组length,lenth[i]表示以下标为i元素结尾的最长上升子序列的长度。
则可以想到如下的转换关系 length[i] = max(length[j])+1,其中0<=j<i并且num[i]>=num[j],用程序实现
如下:
- int cal(const int *num ,int size)
- {
- int *length ,i ,j ,r ,maxl = 1;
- length = (int*)malloc(size<<2);
- for(i = 0 ;i < size ;i ++)
- {
- r = 0;
- for(j = 0 ;j < i ;j ++)
- if(num[j] <= num[i] && length[j] > r)
- r = length[j];
- length[i] = r + 1;
- maxl = r+1 > maxl ? r+1 : maxl;
- }
- free(length);
- return maxl;
- }
上述算法的时间复杂度是O(n^2)的,空间复杂度是O(n)
怎么在O(nlogn)的复杂度下求解最长上升子序列问题呢?
我们知道一般O(n^2)的算法,加入二分的思想后大多数都可以优化到O(nlogn),所以如何在上述算法中利用二分是一个关键。
我们定义一个数组minv,minv[i]表示长度为i的子序列中最小元素的值,该数组一定有如下性质:
对于任意i>j ,一定有minv[i] >= minv[j],也就是说minv一定是升序的。
证明:长度为i的上升子序列中的最后一个元素minv[i]必然大于该序列中的任意一个元素,因为i>j,所以一定有minv[i]>minv[j]。
对于题目中的序列,它对应的minv数组为:{1,2,3,5,7}。
假如现在要在原序列的末尾加上一个10,则minv数组变为{1,2,3,5,7,10}。上述过程不难看出来,如果添加一个数x后再求minv数组,
就是在原来的minv数组中查找位置最靠后并且值小于等于x的元素,设该元素的下标为k,则x和长度为k的子序列可以组成长度为k+1的子序列,
然后更新minv[k+1] = min(x ,minv[k+1])即可。
由于minv是有序的,因此上面的过程可以利用二分查找,从而使时间复杂度降至O(nlogn),用程序实现如下:
- int cal(const int *num ,int size)
- {
- int i ,len=1 ,*minv;
- int left ,right ,mid ,pos;
- minv = (int*)malloc(size<<2);
- minv[0] = num[0];
- for(i = 1 ; i < size ;i ++)
- {
- left = 0 ;
- right = len - 1;
- while(left<=right)
- {
- mid = (left+right)>>1;
- if(minv[mid] > num[i])
- right = mid - 1;
- else
- left = mid + 1;
- }
- pos = right;
- if(pos == len-1)
- {
- minv[len++] = num[i];
- }
- else
- {
- minv[pos+1] = num[i] < minv[pos+1] ? num[i] : minv[pos+1];
- }
- }
- free(minv);
- return len;
- }
- 最长上升子序列O(nlogn)算法
- 最长上升子序列O(nlogn)算法
- 最长上升子序列O(NlogN)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 优化的最长上升子序列LIS算法 O(nlogn)
- 最长上升子序列(LIS)长度的O(nlogn)算法 .
- 最长上升子序列O(nlogn)算法模板
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长严格上升子序列O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 最长上升子序列(LIS)-O(nlogn)算法总结.
- 最长上升(下降)子序列 O(nlogn)
- 如何去面试产品经理
- Cifar实现
- ip default network
- Facebook产品设计总监:设计原则的问题
- 在ubuntu下将普通用户提升到root权限
- 最长上升子序列O(nlogn)算法
- 产品\设计\运营\技术 好文
- UE4信息交互-蓝图类之间的信息交互
- java学习笔记——this关键字
- 『Others』【Vim】The road to grasp VIM
- ubuntu15.10 安装 lampp
- 循环结构中break、continue、return和exit的区别
- POJ - 1716 Integer Intervals(差分约束系统)
- CentOS、Ubuntu、Debian三个linux比较异同