---
# System prepended metadata

title: 0300. Longest Increasing Subsequence
tags: [Leetcode, Dynamic Programming, Longest Increasing Subsequence, Binary Search, Medium, Greedy]

---

# 0300. Longest Increasing Subsequence
###### tags: `Leetcode` `Medium` `Binary Search` `Dynamic Programming` `Greedy` `Longest Increasing Subsequence`
Link: https://leetcode.com/problems/longest-increasing-subsequence/
## 思路 
### Binary Search $O(NlogN)$ $O(N)$
最佳解的核心是**直接建一个 increasing sequence**
每一个新的元素来，如果比现在的increasing sequence的最大值大，就直接往后加，
否则binary search找应该要替换的元素（第一个比它自己大的元素）

后来重新做这道题的时候原本想要用stack解，遇到peek比现在的值大就pop，然后在过程中记录最大的stack size，后来发现不行，因为如果遇到$[0,1,0,3,2,3]$这样的测资，最长的subsequence应该是$[0,1,2,3]$，但是按这种方法，答案就会变成$[0,2,3]$
说明**用stack维持单调栈只适合解决找左边/右边的最大/小值，找一个元素，而不是找整个序列**
**注意line20要用<，而不是<=**
### DP $O(N^2)$ $O(N)$
状态定义：照抄问题 **```dp[i] => s[1:i]```里以```s[i]```结尾的最长的递增子序列的长度**。
状态的转移：寻找最优的前驱状态j，将```dp[i]```与```dp[j]```产生联系。
## Code 
### Binary Search $O(NlogN)$ $O(N)$
```python=
class Solution:
    def lengthOfLIS(self, nums: List[int]) -> int:
        seq = []

        def findPos(num):
            start, end = 0, len(seq)
            while start<end:
                mid = start+(end-start)//2
                if seq[mid]<num:
                    start = mid+1
                else:
                    end = mid
            return start

        for num in nums:
            if not seq or num > seq[-1]:
                seq.append(num)
            else:
                # find the smallest element in the list that is bigger than num
                # and then replace it
                seq[findPos(num)] = num
        return len(seq)
```
```java=
class Solution {
    public int lengthOfLIS(int[] nums) {
        List<Integer> res = new ArrayList<>();
        for(int i = 0;i < nums.length;i++){
            if(res.size() == 0){
                res.add(nums[i]);
                // len++;
            }
            else{
                int currMax = res.get(res.size()-1);
                if(nums[i]>currMax){
                    res.add(nums[i]);
                    // len++;
                }   
                else{
                    int start = 0;
                    int end = res.size();
                    while(start<end){
                        int mid = (start+end)/2;
                        if(res.get(mid)<nums[i]){
                            start = mid+1;
                        }
                        else{
                            end = mid;
                        }
                    }
                    res.set(start, nums[i]);
                }
            }
        }
        return res.size();
    }
}
```
### DP
```java=
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp, 1);
        int ans = 1;
        for(int i=0; i<n; i++){
            for(int j=0; j<i; j++){
                if(nums[j]<nums[i]){
                    dp[i] = Math.max(dp[i], dp[j]+1);
                    ans = Math.max(ans, dp[i]);
                }
            }
        }
        return ans;
    }
}
```