LongestIncreasingSubSequence
- Medium
- tag: DP, BinarySearch
- similar: LCS
Given [10, 9, 2, 5, 6, 3, 7, 101, 18], The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4.
思路
- 最直接就是brute force, 用O(n^2). 外层循环起点, 内层循环该起点所能达到的LIS.
- DP做法: 和Stanford的一样, 定义P[i]为: 以A[i]结尾并包含A[i]的最长LIS的长度. 那么关系就是: $$P[i] = {max(P[k]+1, P[i])\mid A[k] \le A[i] \land k \in [0,i-1]}$$. 这里P[k]要加上1是因为定义的P[i]为以A[i]结尾并包含A[i]的最长LIS的长度, 所以必须包括A[i], 所以加上1.
O(N^2)的DP
- 虽然是DP, 但是复杂度和brute force一样...
- 我在Lintcode里面也是这么做的, 代码如下
public int lengthOfLISOn2(int[] nums) {
if (nums == null || nums.length == 0) return 0;
int[] LIS = new int[nums.length]; // the lis end with nums[i]
int ret = 1;
for (int i = 0; i < nums.length; ++i) {
LIS[i] = 1; // init to be a subsequence with itself
for (int k = 0; k < i; ++k) {
if (nums[k] <= nums[i]) {
LIS[i] = Math.max(LIS[k] + 1, LIS[i]);
}
}
ret = Math.max(ret, LIS[i]);
}
return ret;
}
Geek4Geek: O(nlogn)最佳解法
- 原来还有更好的方法. 还是SOF, 以及Geek讲得好.
- 首先观察, 通过几个简单的例子来找到规律.
- 然后定义state为: S[pos]保存:
smallest integer that ends an increasing subsequence at pos
然后algs就是:
- 若A[i]小于S的最小, 则更新最小.
- 若A[i]大于S的最大, 则extend.
- 否则就找S中的ceil, 即大于A[i]的第一个数的位置, 然后更新.
最后S的长度就是LIS的长度. 但是注意: S[]并不一定是LIS解. 只是长度是LIS的长度. 例如:
2,6,3,4,1,2,9,5,8
, 最后S = {1,2,4,5,8}
找到LIS
- 现在会了O(nlogn)的解法找length, 但是怎么reconstruct这个LIS呢?
- SOF讲了, 但是还没有实现: TODO