# Leetcode 解題速記 300. Longest Increasing Subsequence ###### tags: `LeetCode` `C++` 題敘: --- Given an integer array nums, return the length of the longest strictly increasing subsequence. A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7]. 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 <= nums.length <= 2500` * `-104 <= nums[i] <= 104` 解題筆記: --- 這題一開始看到時直覺想到就是使用DP解題,在看過網路上其他高手的解法後才發現可以使用binary search進一步優化時間複雜度。 我們的思路是,遍歷過整個nums中的數字,`dp[i]`所記錄的是在i+1長度下,最優的子序列尾數。當我們遇到長度相同的子序列時,例如[1,2,8]與[3,4,5],要怎麼判斷哪個比較符合題目的要求呢? 此時,我們只需要考慮子序列中最後一個數字的大小即可,因為越小的尾數,在之後的過程中找到比它更大的數進而擴展的機率更高。上述的例子中,[3,4,5]就會是比較好的子序列。 同理,當我們遇到尾數相同的子序列時,例如[1,2,5]與[3,4,5],在它們長度都為3的情況下,兩個子序列是等價的。但是,當我們將長度降到2,亦即[1,2]與[3,4],此時前者就會優於後者,因為2小於4。 這題的解法就是建立在這個思路基礎上,我們在遍歷nums中所有數字的時候,如果這個數字n比目前dp所記錄的子序列中所有數字都還要大,那我們就擴展目前的子序列,讓這個新數字n成為新的尾數。如果這個數字n的大小恰好在子序列中間的某個位置,我們就使用STL的`lower_bound()`,也就是二分搜,來找到這個位置,然後把其上的數字替換成n。 假設當前dp紀錄的LTS是[1,2]而n=8,因為8>2,所以我們選擇擴增子序列為[1,2,8]。此時這個子序列可以這樣解讀 : ``` [1,2,8] => [1], [*,2], [*,*,8] #長度為i的LTS當下最優的尾數 LTS長度 : i=1 i=2 i=3 ``` 假設下一個數字n為5,因為5<8,所以我們將i=3時最優的數字從8換成5,新的子序列就是[1,2,5] 以此類推繼續往下遍歷,最後取得的`dp.size()`就是我們在所有數字nums中可以找到最好的LTS。 程式碼: --- `Time Complexity : O(nlogn)` ``` cpp class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int> dp; for (int n : nums) { auto it = lower_bound(dp.begin(), dp.end(), n); if (it == dp.end()) { dp.push_back(n); } else { *it = n; } } return dp.size(); } }; ```