Longest Increasing Subsequence
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Longest Increasing Subsequence相关的知识,希望对你有一定的参考价值。
https://leetcode.com/problems/longest-increasing-subsequence/#/solutions
http://www.cnblogs.com/grandyang/p/4938187.html
http://www.cnblogs.com/EdwardLiu/p/5084553.html
先从 O(n^2) 的 DP 做法说起。先从这个开做,是因为 O(n^2) 做
法的普适性高,而且可以无视维度,易于扩展到各种变形与
follow-up 上。
需要返回具体 LIS sequence 的时候,加一个新 array,记录
parent index 一路追踪就可以了~ 和 Largest Divisible Subset
一样。
public class Solution { public int lengthOfLIS(int[] nums) { if (nums==null || nums.length==0) return 0; int res = 1; int len = nums.length; int[] dp = new int[len]; Arrays.fill(dp, 1); for (int i=1; i<len; i++) { for (int j=0; j<i; j++) { if (nums[j] < nums[i]) { dp[i] = Math.max(dp[i], dp[j]+1); if (dp[i] > res) res = dp[i]; } } } return res; } }
下面我们来看一种优化时间复杂度到O(nlgn)的解法,这里用到了二分查找法,所以才能加快运行时间哇。思路是,我们先建立一个数组ends,把首元素放进去,然后比较之后的元素,如果遍历到的新元素比ends数组中的首元素小的话,替换首元素为此新元素,如果遍历到的新元素比ends数组中的末尾元素还大的话,将此新元素添加到ends数组末尾(注意不覆盖原末尾元素)。如果遍历到的新元素比ends数组首元素大,比尾元素小时,此时用二分查找法找到第一个不小于此新元素的位置,覆盖掉位置的原来的数字,以此类推直至遍历完整个nums数组,此时ends数组的长度就是我们要求的LIS的长度,特别注意的是ends数组的值可能不是一个真实的LIS,比如若输入数组nums为{4, 2, 4, 5, 3, 7},那么算完后的ends数组为{2, 3, 5, 7},可以发现它不是一个原数组的LIS,只是长度相等而已,千万要注意这点。
public int lengthOfLIS(int[] nums) { int[] dp = new int[nums.length]; int len = 0; for(int x : nums) { int i = Arrays.binarySearch(dp, 0, len, x); if(i < 0) i = -(i + 1); dp[i] = x; if(i == len) len++; } return len; }
参数:a
- 要搜索的数组fromIndex
- 要搜索的第一个元素的索引(包括)toIndex
- 要搜索的最后一个元素的索引(不包括)key
- 要搜索的值返回:如果它包含在数组的指定范围内,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 插入点 被定义为将键插入数组的那一点:即范围中第一个大于此键的元素索引,如果范围中的所有元素都小于指定的键,则为 toIndex。注意,这保证了当且仅当此键被找到时,返回的值将 >= 0。
以上是关于Longest Increasing Subsequence的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode Longest Increasing Subsequence
Longest Increasing Subsequence
674. Longest Continuous Increasing Subsequence