10k

300. Longest Increasing Subsequence

Question

Given an integer array nums, return the length of the longest strictly increasing subsequence**.

Example 1:

Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.

Example 2:

Input: nums = [0,1,0,3,2,3]
Output: 4

Example 3:

Input: nums = [7,7,7,7,7,7,7]
Output: 1

Constraints:

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

Approach

  1. Use dp, define dp[i] as the ith element, that so far it can be longest subsequence.
    1. The status transform equation is if the element nums[i] is larger than the previous element nums[j], then dp[i] = Math.max(dp[j] + 1, dp[i]);

Code

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int res = 1;
        Arrays.fill(dp, 1);
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
                }
            }
        }
        for (int num : dp) {
            res = Math.max(res, num);
        }
        return res;
    }
}

Follow up

Use O(nlogn) time complexity algorithm.

Algorithm2

The idea is basically to maintain a list, each time there is a large element, append it, otherwise replace a element with a smaller on, so that the whole array become "smaller", and can be longer. Because it's smaller, it can contain more large number.

Code2

class Solution {
    public int lengthOfLIS(int[] nums) {
        List<Integer> list = new ArrayList<>();
        list.add(nums[0]);
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > list.get(list.size() - 1)) {
                list.add(nums[i]);
            } else {
                for (int j = 0; j < list.size(); j++) {
                    if (list.get(j) >= nums[i]) {
                        list.set(j, nums[i]);
                        break;
                    }
                }
            }
        }
        return list.size();
    }
}

But we are required with O(nlogn), so binary search will be leveraged in search the first small element in the else condition.

class Solution {
    public int lengthOfLIS(int[] nums) {
        ArrayList<Integer> sub = new ArrayList<>();
        sub.add(nums[0]);
        
        for (int i = 1; i < nums.length; i++) {
            int num = nums[i];
            if (num > sub.get(sub.size() - 1)) {
                sub.add(num);
            } else {
                int j = binarySearch(sub, num);
                sub.set(j, num);
            }
        }
        
        return sub.size();
    }
    
    private int binarySearch(ArrayList<Integer> sub, int num) {
        int left = 0;
        int right = sub.size() - 1;
        int mid = (left + right) / 2;
        
        while (left < right) {
            mid = (left + right) / 2;
            if (sub.get(mid) == num) {
                return mid;
            }
            
            if (sub.get(mid) < num) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        
        return left;
    }
}
Thoughts? Leave a comment