###### 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;
}
};
```