LIS O(n log n) 详解
来源:互联网 发布:淘宝优惠券在哪领 编辑:程序博客网 时间:2024/05/20 22:28
虽然之前就会了,但是今天用这个方法来求 O(n ^ 2) 的 LIS 中用到的 f[i] 时出了点小差错,所以特立此贴,留作教训。
1.传统 O(n ^ 2) LIS
用 DP 的原理。设 f[i] 为 以第i个元素结尾的上升子序列的最大长度。易得状态转移方程 f[i] = max{ f[j] + 1 | num[j] < num[i], j < i}。
2.O(n log n) LIS
设h[i]为 长度为 i 的上升子序列的结尾元素的最小值。很明显,这个 h[i] 是个单调递增的数组。
证明:如果h[i + 1] < h[i],那么长度为 i 的子序列可以索性不要 h[i] 这个元素,而是让 h[i + 1] 结尾,所以 h[i] 不会大于 h[i + 1]。
如果有h[i] = h[i + 1],考虑长度为 i + 1的子序列是如何生成的。它必然是由长度为 i 的子序列加上一个更大的数组成的。现在长度为 i 的子序列的结尾的最小值为 h[i],那么长度为 i + 1 的子序列的结尾不可能等于 h[i],否则子序列就不是严格上升的了。
因此 h[i] 是个单调递增的数组。
怎么求最长上升子序列的长度呢?
很明显,如果我们按正确的算法操作下去,最后的答案就是 数组h 的大小。那怎么操作呢?
如果 h.back() < num,就把 num 加入 h 的末尾(push_back);否则在 h 中二分查找,找到第一个大于等于 num 的数(lower_bound),把这个数改成 num。只要知道了 h[i] 的含义,这个操作应该就不难理解。
3.用 2 的方法求 1 的 f 数组
如果我们要求 f 数组,也可以用 2 的方法来求。如果 h.back() < num,那么 f[i] 就等于 push_back(num) 之后的 h.size()。如果 h.back() >= num,设二分查找找到的 iterator 为 it,那么 f[i] = it - h.begin() + 1。
4.注意
如果是严格上升下降,应当用 lower_bound,否则用 upper_bound。同时注意把 num push_back 到 h 中时到底要求满足的是 小于 还是 小于等于。
- LIS O(n log n) 详解
- hdu 1025&hdu 1025 LIS(O(n*n)和O(n*log(n)))两种解法
- POJ 3671 (n log n,LIS)
- num的n次方 O(log(n))
- 单调栈/LIS的log n做法
- lis o(n^2)//hdu 1087
- HDOJ 1025 LIS O(nlog(n))
- hdu 1025 (LIS(n*log(n)时间复杂度))
- 求N!最后非0位 O(N log N)
- LIS问题(转换成LCS解法 O(n*n))
- 3070 Fibonacci(O(log n)求解 )
- 快速幂( O(log n) )
- SkipList时间复杂度分析O(log n)
- combSort 复杂度O(n*log(n)) 虽然是两层循环
- fibonacci 数列实现 log(n) and O(n)
- LIS 的 n*log 算法 ———二分维护
- 【KMP O(n)算法详解】
- 计数排序详解:O(n)
- KNN(NearestNeighbor)临近算法,自然语言讲解
- I2C、SPI和UART、
- Mybatis学习笔记一
- Struts2自动装配(+入门)
- 爬虫基础-- 正则基础
- LIS O(n log n) 详解
- Maven安装
- 深度学习所需的python-学习笔记5
- Java学习心得之面向对象(一)
- hilbert矩阵
- CentOS7编译WD My Cloud下的SVN(Subversion)(附编译好的SVN的链接)
- Spring系列之Spring常用注解总结
- 浅析Android下的Android.mk文件(二)
- fibonacci求解