LeetCode 300. Longest ascending subsequence

9-8 LIS problem long increasing subsequence

Title: LeetCode 300. Longest ascending subsequence

Given an unordered array of integers, find the length of the longest ascending subsequence.

Example:

Input: [10,9,2,5,3,7101,18]
Output: 4
Explanation: the longest ascending subsequence is [2,3,7101], and its length is 4.
Explain:

There may be multiple combinations of the longest ascending subsequences. You only need to output the corresponding length.
The time complexity of your algorithm should be O(n2).
Advanced: can you reduce the time complexity of the algorithm to O(n log n)?

Violent solution: select all subsequences for judgment.
Dynamic planning:
Where "state" is defined: LIS(i) represents the length of the longest ascending subsequence ending with the ith number. That is, LIS(i) represents [0 In the range of, I], select the length of the longest ascending subsequence that can be obtained by nums[i].
According to the definition of state, determine the transfer of state:
LIS(i) = when (J < I), Max {1 + LIS (J) if nums [i] > nums [J]}
import java.util.Arrays;

/// 300. Longest Increasing Subsequence
/// https://leetcode.com/problems/longest-increasing-subsequence/description/
///Memory search
///Time complexity: O(n^2)
///Spatial complexity: O(n)
public class Solution1 {

    private int[] memo;

    public int lengthOfLIS(int[] nums) {

        if(nums.length == 0)
            return 0;

        memo = new int[nums.length];
        Arrays.fill(memo, -1);
        int res = 1;
        for(int i = 0 ; i < nums.length ; i ++)
            res = Math.max(res, getMaxLength(nums, i));

        return res;
    }

    // Length of the longest ascending subsequence ending in nums[index]
    private int getMaxLength(int[] nums, int index){

        if(memo[index] != -1)
            return memo[index];

        int res = 1;
        for(int i = 0 ; i <= index-1 ; i ++)
            if(nums[index] > nums[i])
                res = Math.max(res, 1 + getMaxLength(nums, i));

        return memo[index] = res;
    }

    public static void main(String[] args) {

        int nums1[] = {10, 9, 2, 5, 3, 7, 101, 18};
        System.out.println((new Solution1()).lengthOfLIS(nums1));
        // 4

        // ---

        int nums2[] = {4, 10, 4, 3, 8, 9};
        System.out.println((new Solution1()).lengthOfLIS(nums2));
        // 3

        // ---

        int nums3[] = {2, 2};
        System.out.println((new Solution1()).lengthOfLIS(nums3));
        // 1

        // ---

        int nums4[] = {1, 3, 6, 7, 9, 4, 10, 5, 6};
        System.out.println((new Solution1()).lengthOfLIS(nums4));
        // 6
    }
}
import java.util.Arrays;

/// 300. Longest Increasing Subsequence
/// https://leetcode.com/problems/longest-increasing-subsequence/description/
///Memory search
///Time complexity: O(n^2)
///Spatial complexity: O(n)
public class Solution2 {

    public int lengthOfLIS(int[] nums) {

        if(nums.length == 0)
            return 0;

        // memo[i] represents the length of the longest ascending subsequence ending in nums[i]
        int memo[] = new int[nums.length];
        Arrays.fill(memo, 1);
        for(int i = 1 ; i < nums.length ; i ++)
            for(int j = 0 ; j < i ; j ++)
                if(nums[i] > nums[j])
                    memo[i] = Math.max(memo[i], 1 + memo[j]);

        int res = memo[0];
        for(int i = 1 ; i < nums.length ; i ++)
            res = Math.max(res, memo[i]);

        return res;
    }

    public static void main(String[] args) {

        int nums1[] = {10, 9, 2, 5, 3, 7, 101, 18};
        System.out.println((new Solution2()).lengthOfLIS(nums1));
        // 4

        // ---

        int nums2[] = {4, 10, 4, 3, 8, 9};
        System.out.println((new Solution2()).lengthOfLIS(nums2));
        // 3

        // ---

        int nums3[] = {2, 2};
        System.out.println((new Solution2()).lengthOfLIS(nums3));
        // 1

        // ---

        int nums4[] = {1, 3, 6, 7, 9, 4, 10, 5, 6};
        System.out.println((new Solution2()).lengthOfLIS(nums4));
        // 6
    }
}

import java.util.Arrays;

/// 300. Longest Increasing Subsequence
/// https://leetcode.com/problems/longest-increasing-subsequence/description/
///
///In this chapter, we introduce the dynamic programming method to solve the LIS problem. The time complexity is O(nlogn)
///LIS has a classical and ingenious dynamic programming method, whose time complexity is O(nlogn)
///Here are the reference code and simple notes. If you need more detailed explanation, you can search and learn on the Internet by yourself
///Through this example, let's also understand how to change the state definition of dynamic planning,
///It brings about significant differences in problem-solving methods, even huge optimizations on the order of time complexity
///
///Time complexity: O(nlogn)
///Spatial complexity: O(n)
public class Solution {

    public int lengthOfLIS(int[] nums) {

        if(nums.length == 0)
            return 0;

        // dp[i] represents the increment subsequence with the longest length of I and the minimum value of the last number
        int dp[] = new int[nums.length + 1];
        Arrays.fill(dp, Integer.MIN_VALUE);

        int len = 1;
        dp[1] = nums[0];
        for(int i = 1 ; i < nums.length ; i ++)
            if(nums[i] > dp[len]){
                len ++;
                dp[len] = nums[i];
            }
            else{
                // Our dp array will be a monotonically increasing array, so we can use binary search method
                int index = lowerBound(dp, 0, len, nums[i]);
                if(dp[index] != nums[i])
                    dp[index] = Math.min(dp[index], nums[i]);
            }

        return len;
    }

    // lowerBound finds the index of the first element greater than or equal to target in the range of arr[l...r]
    private int lowerBound(int[] arr, int l, int r, int target){

        int left = l, right = r + 1;
        while(left != right){
            int mid = left + (right - left) / 2;
            if(arr[mid] >= target)
                right = mid;
            else // arr[mid] < target
                left = mid + 1;
        }
        return left;
    }

    public static void main(String[] args) {

        int nums1[] = {10, 9, 2, 5, 3, 7, 101, 18};
        System.out.println((new Solution()).lengthOfLIS(nums1));
        // 4

        // ---

        int nums2[] = {4, 10, 4, 3, 8, 9};
        System.out.println((new Solution()).lengthOfLIS(nums2));
        // 3

        // ---

        int nums3[] = {2, 2};
        System.out.println((new Solution()).lengthOfLIS(nums3));
        // 1

        // ---

        int nums4[] = {1, 3, 6, 7, 9, 4, 10, 5, 6};
        System.out.println((new Solution()).lengthOfLIS(nums4));
        // 6
    }
}

Keywords: Java Programming

Added by VapiD on Wed, 18 Dec 2019 17:50:49 +0200