Longest Increasing Subsequence

DPGreedyBinary Search
https://leetcode.com/problems/longest-increasing-subsequence

# Solution

Let nn be the length of the array.

The brute force O(n3)O(n^3) solution is omitted.

# Follow Up

Could you come up with the O(n2)O(n^2) solution?

# DFS Recursion w/ Memo

dfs(i)dfs(i) 表示以 nums[i] 结尾的最长递增子序列(LIS)的长度。

dfs(i)=max(dfs(j))+1for j<i and nums[j]<nums[i] \text{dfs}(i) = \max{(\text{dfs}(j))} + 1 \text{\quad for } j < i \text{ and } \text{nums}[j] < \text{nums}[i]
def lengthOfLIS(self, nums: List[int]) -> int:
    # dfs(i): 以 nums[i] 结尾的LIS
    @cache
    def dfs(i):
        res = 0
        for j in range(i):
            if nums[j] < nums[i]:
                res = max(res, dfs(j))
        return res + 1 # 1 means num[i]
    
    n = len(nums)
    return max(dfs(i) for i in range(n))
1
2
3
4
5
6
7
8
9
10
11
12
int lengthOfLIS(vector<int>& nums) {
    int n = nums.size();
    vector<int> memo(n);
    auto dfs = [&](this auto&& dfs, int i) -> int {
        int& res = memo[i]; // reference here
        if (res > 0) { // having calculated
            return res;
        }
        for (int j = 0; j < i; j++) {
            if (nums[j] < nums[i]) {
                res = max(res, dfs(j));
            }
        }
        return ++res;
    };
    int ans = 0;
    for (int i = 0; i < n; i++) {
        ans = max(ans, dfs(i));
    }
    return ans;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# DP

Complexity

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

def lengthOfLIS(self, nums: List[int]) -> int:
    # 以 nums[i] 结尾的LIS
    n = len(nums)
    dp = [0 for _ in range(n)]
    for i in range(n):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j])
        dp[i] += 1
    return max(dp)
1
2
3
4
5
6
7
8
9
10

Could you improve it to O(nlogn)O(n \log n) time complexity?

g[i] 表示长为 i+1 的上升子序列的末尾元素的最小值。

Complexity

time: O(nlogn)O(n \log n)
space: O(n)O(n)

def lengthOfLIS(self, nums: List[int]) -> int:
    g = []
    for x in nums:
        j = bisect_left(g, x)
        if j == len(g):
            g.append(x)
        else:
            g[j] = x
    return len(g)
1
2
3
4
5
6
7
8
9