Longest Increasing Subsequence Leetcode
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18]
,
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
哎竟没有发现这道题做过了。。。感觉dp都忘光了。。。首先要识别这是dp,遇到问题可以想想这道题能不能递推。
public class Solution { public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int[] len = new int[nums.length]; Arrays.fill(len, 1); for (int i = 0; i < nums.length; i++) { for (int j = 0; j < i; j++) { if (nums[i] > nums[j]) { len[i] = Math.max(len[i], len[j] + 1); } } } Arrays.sort(len); return len[nums.length - 1]; } }
但这个解法是O(n^2)的,follow up要求O(nlongn)怎么办呢? 这就用到一个特殊排序算法,耐心排序了。解法就是维护一个排序的数组,每遍历一个数,就在这个数组中二分查找,如果比最小的数还小,就把最小数替换成这个数,如果比最大的数还大,就把这个数排在最大的数后面,如果在中间,就用它替换第一个比它大的数。
这样,这个数组的长度就是最长增长子串的长度。
改进之后速度从48ms变成了2ms,显著提升。
public class Solution { public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int[] tail = new int[nums.length]; Arrays.fill(tail, Integer.MIN_VALUE); int size = 0; for (int i = 0; i < nums.length; i++) { int start = 0; int end = size; while (start + 1 < end) { int m = (end - start) / 2 + start; if (tail[m] > nums[i]) { end = m; } else { start = m; } } if (nums[i] <= tail[start]) { tail[start] = nums[i]; } else if (nums[i] <= tail[end]) { tail[end] = nums[i]; } else if (nums[i] > tail[end]) { tail[size] = nums[i]; size++; } } return size; } }
我写的代码还略显冗余,对照top solution更改版:
public class Solution { public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int[] tail = new int[nums.length]; int size = 0; for (int i = 0; i < nums.length; i++) { int start = 0; int end = size; while (start != end) { int m = (end - start) / 2 + start; if (tail[m] >= nums[i]) { end = m; } else { start = m + 1; } } tail[start] = nums[i]; if (start == size) { size++; } } return size; } }
这个版本其实可以看出功力的,首先不用fill最小值了,其次不用比较那么多次了。挺妙的,感觉我面试不一定能写的出来。。。尽量学习吧。。。
ps: 这道题需要注意等号加在哪里,最长增长子串要求是增长的,所以相等的不包括。
这个算法不熟悉还是到时候回顾一下吧。