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: 这道题需要注意等号加在哪里,最长增长子串要求是增长的,所以相等的不包括。

这个算法不熟悉还是到时候回顾一下吧。

posted @ 2017-02-28 09:52  璨璨要好好学习  阅读(188)  评论(0编辑  收藏  举报