九度OJ 1533 最长上升子序列 (基于贪心和二分查找)
来源:互联网 发布:网络有利还是有害 编辑:程序博客网 时间:2024/06/05 05:44
- 题目描述:
给定一个整型数组, 求这个数组的最长严格递增子序列的长度。 譬如序列1 2 2 4 3 的最长严格递增子序列为1,2,4或1,2,3.他们的长度为3。
- 输入:
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数n(1<=n<=100000):代表将要输入的序列长度
输入的第二行包括n个整数,代表这个数组中的数字。整数均在int范围内。
- 输出:
对于每个测试案例,输出其最长严格递增子序列长度。
- 样例输入:
44 2 1 351 1 1 1 1
- 样例输出:
21
【思路分析】
求LIS的经典问题,用到的不是DP里面O(n*n)的方法,而是用了基于贪心、二分查找的O(nlogn)方法(为什么没有命名成XXX算法 = =)。
设a[n]为原序列,d[n]为长度为n的上升子序列的最后一个元素,当有多个长度为n的上升子序列时,取这些子序列中末尾最小的元素作为d[n]的值。为什么选最小的呢?因为最小的最有“潜力”(贪心)。举个例子,假设原序列为:2,1,8,3,7,5,6,对于d[3],长度为3的上升子序列有1,3,7和1,3,5两个,那么d[3]取值为5,即末尾最小的元素。因为在这个子序列后可能存在x满足 5 < x < 7(即x == 6),因此要是子序列确定为1,3,7的话,则显然不如1,3,5,6长。可见,d数组中的元素是单调递增的。
有了上述的贪心策略,便可以进行下面的操作了。首先,令len = 1,d[1] = a[1],当a[i] > d[len]时,有d[++len] = a[i],即加入新的元素来扩充上升子序列;否则,从d[1]到d[len - 1]找到一个j,使得a[i]满足: d[j - 1] < a[i] < d[j],这时有d[j] = a[i],即用a[i]来替换d[j](也就是a[i]比d[j]更有“潜力”)。又由于d数组是单调递增的,因此可以用二分查找O(logn)很快找到j的值。
最后用a = {2,1,5,3,6,4,8,9}这个序列来过一遍上述的流程。首先,len = 1,d[1] = a[1] = 2。则a[i],len,d[len]的值的变化见下表:
代码如下:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int maxn = 100005;int n;int a[maxn];int d[maxn];//记录长度为i的上升子序列最后一个元素的值int binSearch(int key,int left,int right){ while(left <= right) { int mid = (left + right) >> 1; if(key > d[mid] && key <= d[mid + 1])//贪心策略 { return mid; } else if(key > d[mid]) { left = mid + 1; } else { right = mid - 1; } } return 0;}int LIS(int n){ d[1] = a[1]; int len = 1; int j = 0; for(int i = 2;i <= n;i++) { if(d[len] < a[i]) { j = ++len;//直接向后插入 } else { j = binSearch(a[i],1,len) + 1;//找到替换位置 } d[j] = a[i]; } return len;}void init(){ for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); }}void solve(){ printf("%d\n",LIS(n));}int main(){ while(scanf("%d",&n) != EOF) { init(); solve(); } return 0;}
- 九度OJ 1533 最长上升子序列 (基于贪心和二分查找)
- 九度OJ 1533 最长上升子序列 -- 动态规划
- POJ2533, 最长上升子序列(贪心+二分查找时间复杂度O(nlogn))
- 九度 oj 题目1480:最大上升子序列和
- 九度OJ-1480:最大上升子序列和
- 最长上升子序列 (二分 nlogn)
- 最长上升子序列 (二分)
- UVa 10534 - Wavio Sequence DP+最长上升子序列(严格上升)+二分查找(nlogn)
- 题目1533:最长上升子序列-九度
- hdu 1025 二分查找+最长上升子序列
- 使用二分查找求解最长上升子序列
- 九度OJ 1500 出操队形 -- 动态规划(最长上升子序列)
- 【模版】二分查找、最长上升子序列(LIS)、最长下降子序列模版
- hdu 5256 序列变换(最长上升子序列&&二分)
- 最长上升子序列的dp和二分求法
- HDU 1257(贪心;动态规划(最长上升子序列))
- hdu 5773 贪心+最长上升子序列
- bailian--oj--2757(最长上升子序列)
- UDP传输中文乱码、异常解决
- C++成员变量的初始化顺序问题
- 设计模式之单例模式
- Android入门——利用Canvas完成绘制点、圆、直线、路径、椭圆、多边形等2D图形
- 微信公众平台初试
- 九度OJ 1533 最长上升子序列 (基于贪心和二分查找)
- android studio 代码修复提示快捷键
- 用链表实现队列
- java内省机制及PropertyUtils使用方法
- iOS中的动画总体预览
- jQuery源码分析之$.index函数
- 机器学习(三)线性回归和梯度下降法
- 面向对象的php之类解耦的好处
- web链接与tab切换对应的效果