---
# System prepended metadata

title: 300. Longest Increasing Subsequence
tags: [Leetcode, binary search, medium, python, c++, Top 100 Liked Questions, dynamic programming]

---

###### tags: `Leetcode` `medium` `dynamic programming` `binary search` `python` `c++` `Top 100 Liked Questions`

# 300. Longest Increasing Subsequence

## [題目連結:] https://leetcode.com/problems/longest-increasing-subsequence/

## 題目:
Given an integer array nums, return the length of the longest strictly increasing **subsequence**.
* A subsequence is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.

**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
```

## 解題想法:
* 求數組中: 嚴格遞增的子序列(不用連續，只要元素順序不變即可)

* 法1:使用DP 
    * 定義dp[i]表示**從頭到num[i]最長subsequence**
    * 雙迴圈遍歷
        * 第一圈:for **i** in range(len(nums))
        * 第二圈 for **j** in range(i)
    * 若nums[j]<nums[i]，則可以判斷
        * dp[i]=max(dp[i],dp[j]+1)
        * 原本的or繼承後+1
    * 由於第二迴圈，每次皆從頭判斷，因此time: O(n^2)

## Python_Sol1: DP
``` python=
class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        #time:O(n^2)
        dp=[1]*len(nums)
        #dp[i]表示從頭到num[i]最長subsequence
        res=float('-inf')
        for i in range(len(nums)):
            for j in range(i):
                if nums[j]<nums[i]:
                    dp[i]=max(dp[i],dp[j]+1)
            res=max(res,dp[i])
        return res

result=Solution()
ans=result.lengthOfLIS(nums = [10,9,2,5,3,7,101,18])
print(ans)
```

* 法2: 使用Binary Search概念
    * time: **O(NlogN)**
    * Step1: 
        * 將nums[0]先加入到res
    * Step2:
        * 依序遍歷數組後面的數:
            * **Case1**:若當前數字比res[-1]更大，則將此數字加到res
            * **Case2**:若當前數字比res[0]更小，則取代res[0]
            * **Case3**:若當前數字大小在res中間，則選mid的位置，當前數字取代nums[mid]
            * mid:即為res中第一個比當前數字大的位置
    * 最後答案即為len(res)
        * **然而res中的數字組合不一定是合法的!!**

* trace:
``` python=
nums = [10,9,2,5,3,7,101,18]
res=[10]

for i in range(1,len(nums)):
* loop1: 9
case2: 9<res[0]
-> res=[9]

* loop2: 2
case2: 2<res[0]
-> res=[2]

* loop3: 5
case1: 5>res[-1]
-> res=[2,5]

* loop4: 3
case3: -> res=[2,3]

* loop5: 7
case1: -> res=[2,3,7]

* loop6: 101
case1: -> res=[2,3,7,101]

* loop7: 18
case3: -> res=[2,3,18,101]

注意!! 此時res中順序: 並不是合法解!! 
但res的長度始終保持著當前最長序列的長度~~

final ans: len(res)=4 
```

## Python_Sol2:
``` python=
class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        #time: O(nlogn)
        if len(nums)==0:
            return 0
        res=[nums[0]]
        for i in range(1,len(nums)):
            #若新的值 比res最後一個大 則直接加入
            if nums[i]>res[-1]:
                res.append(nums[i])
            #若小於res[0] 則取代res[0]
            elif nums[i]<res[0]:
                res[0]=nums[i]
            else: #若在中間 選mid的位置 nums[i]取代nums[mid]
                mid = self.findMid(res,nums[i])
                res[mid]=nums[i]
        return len(res)
    
    def findMid(self,res,num):
        head=0
        tail=len(res)-1
        while head<=tail:
            mid=(head+tail)//2
            if res[mid]==num:
                return mid
            elif res[mid]>num:
                tail=mid-1
            else:
                head=mid+1
        return head

result=Solution()
ans=result.lengthOfLIS(nums = [10,9,2,5,3,7,101,18])
print(ans)
```

## C++:
``` cpp=
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if (nums.size()==0)
            return 0;
        vector<int> res;
        res.push_back(nums[0]);
        for (int i=1; i<nums.size(); i++){
            if (nums[i]>res.back())
                res.push_back(nums[i]);
            else if (nums[i]<res[0])
                res[0]=nums[i];
            else{
                int mid=find(res,nums[i]);
                res[mid]=nums[i];
            }
        }
        return res.size();
    }

    int find(vector<int>& res, int val){
        int head=0, tail=res.size()-1;
        while (head<=tail){
            int mid=(head+tail)/2;
            if (res[mid]==val)
                return mid;
            else if (res[mid]<val)
                head=mid+1;
            else
                tail=mid-1;
        }
        return head;
    }
};
```