[LintCode] Longest Increasing Subsequence

Given a sequence of integers, find the longest increasing subsequence (LIS).

You code should return the length of the LIS.

Clarification

What's the definition of longest increasing subsequence?

  • The longest increasing subsequence problem is to find a subsequence of a given sequence in which the subsequence's elements are in sorted order, lowest to highest, and in which the subsequence is as long as possible. This subsequence is not necessarily contiguous, or unique.

  • https://en.wikipedia.org/wiki/Longest_increasing_subsequence

Example

For [5, 4, 1, 2, 3], the LIS is [1, 2, 3], return 3
For [4, 2, 4, 5, 3, 7], the LIS is [2, 4, 5, 7], return 4

---------------------------------------------------------------------------------------------------------------------------------------------

解法1 O(n^2):

f[i] 表示(从前任意某个木桩)跳到第i个木桩,最多踩过多少根木桩 • function: f[i] = max{f[j] + 1}, j必须满足 j < i && nums[j] < nums[i]

initialize: f[0..n-1] = 1

answer: max{f[0..n-1]}

public class Solution {
    /**
     * @param nums: The integer array
     * @return: The length of LIS (longest increasing subsequence)
     */
    public int longestIncreasingSubsequence(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int n = nums.length;
        int[] f = new int[n];
        //f(i) the longest increasing subsequence from any previous positon to i
        //Initialize: all the f(i) at least equal to 1
        Arrays.fill(f, 1);
        
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    f[i] = Math.max(f[i], f[j] + 1); 
                }
            }
        }
        
        int rst = Integer.MIN_VALUE;
        for(int i =0; i < n; i++) {
            if (f[i] > rst) {
                rst = f[i];
            }
        }
        
        return rst;
    }
}
 

 

解法二 o(nlogn)

这道题是用binary search的思想来达到nlogn的级别。

在这里定义一个数组minLast, minLast[i]代表长度位i的时候,上升数列最小的结尾是什么值。例如{4, 2, 4, 5, 3, 7}minLast[1] = 1,这是因为长度为1的时候,上升数列最小的结尾是2;  minLast[2] =3, 这是因为长度为2的时候,上升数列最小的结尾是3; minLast[3] = 5; minLast[4] = 7。这样我们就能看到最大的minLast有价值的时候对应的i的值,就是最长的上升数列的size。

为了能实现这个想法,我们先要初始一个minLast的数组(比给定数组大一位),第0位位最小值,其余位位最大值。循环给定的数组,用binary search在minLast里面找到第一个>=nums[i]的index。然后override minLast[index]=nums[i]。这么做是为了保证在index上永远存的是根据nums的order得到的长度为index的最小值。比如最开始minLast[1]=4,但当循环到2的时候,因为4是第一个比2大的数,这个时候如果长度为1的话,上升序列的最小的结尾的值应该是2而不是4。 以此类推。特别注意的是minLast数组的值可能不是一个真实的LIS。用上面的例子,最后minLast应该是{min, 2, 3, 4, 7, max, max}。但lis其实是{2,4,5,7}

public class Solution {
    /*
     * @param nums: An integer array
     * @return: The length of LIS (longest increasing subsequence)
     */
    public int longestIncreasingSubsequence(int[] nums) {
        int[] minLast = new int[nums.length + 1];
        Arrays.fill(minLast, Integer.MAX_VALUE);
        minLast[0] = Integer.MIN_VALUE;

        
        for (int i = 0; i < nums.length; i++) {
            // find the first number in minLast >= nums[i]
            int index = binarySearch(minLast, nums[i]);
            minLast[index] = nums[i];
        }
        
        for (int i = nums.length; i >= 1; i--) {
            if (minLast[i] != Integer.MAX_VALUE) {
                return i;
            }
        }
        
        return 0;
    }
    
    // find the first number >= num
    private int binarySearch(int[] minLast, int num) {
        int start = 0, end = minLast.length - 1;
        while (start + 1 < end) {
            int mid = (end - start) / 2 + start;
            if (minLast[mid] < num) {
                start = mid;
            } else {
                end = mid;
            }
        }
        if (minLast[start] >= num) return start;
        return end;
    }
}

 

posted on 2017-05-26 11:05  codingEskimo  阅读(98)  评论(0编辑  收藏  举报

导航