leetcode300. 最長遞增子序列(動態規劃 貪心 二分)
阿新 • • 發佈:2021-10-20
連結:https://leetcode-cn.com/problems/longest-increasing-subsequence/
題目
給你一個整數陣列 nums ,找到其中最長嚴格遞增子序列的長度。
子序列是由陣列派生而來的序列,刪除(或不刪除)陣列中的元素而不改變其餘元素的順序。例如,[3,6,2,7] 是陣列 [0,3,1,6,2,2,7] 的子序列。
用例
示例 1:
輸入:nums = [10,9,2,5,3,7,101,18]
輸出:4
解釋:最長遞增子序列是 [2,3,7,101],因此長度為 4 。
示例 2:
輸入:nums = [0,1,0,3,2,3]
輸出:4
示例 3:
輸入:nums = [7,7,7,7,7,7,7]
輸出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
進階:
你可以設計時間複雜度為 O(n2) 的解決方案嗎?
你能將演算法的時間複雜度降低到O(n log(n)) 嗎?
思路
方法一
動態規劃 記錄第一個位置到每一個位置最大距離 O(n^2)
注意*max_element(dp.begin(),dp.end());取陣列最大值
轉移方程dp[i]=max(dp[j]+1,dp[i]) ,nums[i]>nums[j],i>j
class Solution { public: int lengthOfLIS(vector<int>& nums) { int n=nums.size(); vector<int>dp(n,1); for(int i=0;i<n;++i){ for(int j=0;j<i;++j){ if(nums[j]<nums[i]){ dp[i]=max(dp[i],dp[j]+1); } } } return *max_element(dp.begin(),dp.end()); } };
方法二
貪心
維護一個數組,記錄在長度固定的情況下,結尾最小的那個元素的數值
對原序列進行遍歷,將每位元素二分插入 cell 中。
如果 cell 中元素都比它小,將它插到最後
否則,用它覆蓋掉比它大的元素中最小的那個。
思想就是讓 cell 中儲存比較小的元素。這樣,cell 未必是真實的最長上升子序列,但長度是對的。
class Solution { public: int lengthOfLIS(vector<int>& nums) { int len=1,n=nums.size(); vector<int>d(n+1,0); d[len]=nums[0]; for(int i=1;i<n;++i){ if(nums[i]>d[len]){ d[++len]=nums[i]; }else{ int l=1,r=len,pos=0;//說明所有數都比nums[i]大,需要更新d陣列 while(l<=r){ int mid=(l+r)>>1; if(d[mid]<nums[i]){ pos =mid; l=mid +1; }else{ r=mid-1; } } d[pos+1]=nums[i]; } } return len; } };