LC 0300 [M] Longest Increasing Subsequence (LIS) - ALawliet/algorithms GitHub Wiki

the binary search solution is recommended and optimal and genius

# O(nlogn) solution with binary search
class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:        
        def binarySearch(A, x):
            l = 0
            r = len(A) - 1
            while l <= r:
                m = (l + r) // 2
                if A[m] == x:
                    return m
                elif A[m] < x:
                    l = m + 1
                elif A[m] > x:
                    r = m - 1
            return l
        
        res = []
        for x in nums:
            # l = binarySearch(res, x)
            l = bisect_left(res, x)
            if l == len(res):
                res.append(x)
            else:
                res[l] = x
        return len(res)

here note the final solution is not at [-1] but the max of the DP table

most intuitive

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        if not nums: return 0
        n = len(nums)
        T = [1] * n
        for r in range(1, n):
            for l in range(r):
                if nums[r] > nums[l]:
                    T[r] = max(T[r], T[l] + 1)
        return max(T)
class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        LIS = [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]:
                    LIS[i] = max(LIS[i], 1 + LIS[j])
        
        return max(LIS)

recursion memoization

class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:        
        @cache
        def dp(r):
            res = 1
            for l in range(r):
                if nums[r] > nums[l]:
                    res = max(res, dp(l) + 1)
            return res
        
        n = len(nums)
        res = 1
        for r in range(n):
            res = max(res, dp(r))
        return res
class Solution():
    def lengthOfLIS(self, nums):
        n = len(nums)
        
        memo = [0 for i in range(n)]
        
        def maxAt(r):
            if memo[r]: return memo[r]

            res = 1
    
            for l in range(r):
                if nums[r] > nums[l]:
                    res = max(res, maxAt(l) + 1)

            memo[r] = res
            return res
        
        res = 1
        for r in range(n):
            res = max(res, maxAt(r))
        return res