Post

LC 300 - Longest Increasing Subsequence

LC 300 - Longest Increasing Subsequence

Question

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

Example 1:

1
2
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:

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

Example 3:

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

Constraints:

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

Follow up: Can you come up with an algorithm that runs in O(n log(n)) time complexity?

Question here and solution here

Solution

concept

memoization

We use DFS to scan through index i. The key part is to cache an array where the LIS (from i till end of num, i,e, the behind part of the array) at index i is cached. At each index i, we will run through i+1 till end of nums to get the LIS at that index i. And this is the value we will cache. image

bottom up

We iterate the nums array from reverse, at each index i , we will run check for LIS if the condition of strictly increasing order is met, and if yes we will use the cached value. The sub problem here is to figure out the LIS at each index (LIS from the array from i to end of nums) 1 means itself, which is always true because the number itself is a candidate of LIS. image

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution:
	"""
	brute force
	TLE
	"""
    def lengthOfLIS(self, nums: List[int]) -> int:
        
        def dfs(i):
            LIS = 1
            for j in range(i + 1, len(nums)):
                if nums[i] < nums[j]:
                    LIS = max(LIS, 1 + dfs(j))
            return LIS

        return max(dfs(i) for i in range(len(nums)))
        
class Solution:
	"""
	top down: memoization
	"""
    def lengthOfLIS(self, nums: List[int]) -> int:
        cache = [-1] * len(nums) # LIS at index i

        def dfs(i):
            if cache[i] != -1:
                return cache[i]

            LIS = 1
            for j in range(i + 1, len(nums)):
                if nums[i] < nums[j]:
                    LIS = max(LIS, 1 + dfs(j))
            cache[i] = LIS
            return cache[i]

        return max(dfs(i) for i in range(len(nums)))

class Solution:
	"""
	bottom up solution
	"""
    def lengthOfLIS(self, nums: List[int]) -> int:
        dp = [1]*len(nums)

        for i in range(len(nums)-1, -1, -1):
            for j in range(i+1, len(nums)):
                if nums[i] < nums[j]:
                    dp[i] = max(dp[i], 1 + dp[j])
        
        return max(dp)

Complexity

time: $O(n^2)$
space: $O(n)$

This post is licensed under CC BY 4.0 by the author.