LeetCode300.最長遞增子序列
力扣題目連結(opens new window)
給你一個整數陣列 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
動態規劃思路講解
- 我之前也講過一篇最長上升子序列的文章,也可以去看看,本文基於線性dp:最長上升子序列 - Tomorrowland_D - 部落格園 (cnblogs.com))來詳細講解這道題的思路
狀態變數以及其含義
- 我們設定狀態變數dp[i],表示
以nums[i]為結尾的最長上升子序列的長度
- 我們舉個例子,以示例1為例,我們來推導一下為什麼可以用
dp[i]
來表示以nums[i]為結尾的最長上升子序列 - nums陣列: [10,9,2,5,3,7,101,18]
- 以10結尾的最長上升子序為:[10]
- 以9為結尾的最長上升子序列為:[9]
- 以2為結尾的最長上升子序列為:[2]
- 以5為結尾的最長上升子序列為:[2,5]
- 以3為結尾的最長上升子序列為:[2,3]
- 以7為結尾的最長上升子序列為:[2,3,7]
- 以101為結尾的最長上升子序列為:[2,3,7,101]
- 以18為結尾的最長上升子序列為:[2,3,7,18]
- 由上面的分析可知,以101為結尾的最長上升子序列是我們要求的最終的結果,並且這個結果的狀態可以由前面的狀態推出,因此我們設立
dp[i]
這個狀態變數表示以nums[i]
為結尾的最長上升子序列。
遞推公式:
-
我們可以設立兩個指標
i,j
來進行操作,i
指標來遍歷nums
的每一個元素,j
指標來遍歷nums[i]
之前的所有元素,由於我們要找出最大的上升子序列,所以說每個元素我們都要找到nums中在這個元素之前的所有比這個元素要小的元素,這樣才能儘可能的構成最大的遞增子序列。 -
所以說我們使用i,j指標來遍歷字串。
-
當
nums[i]>nums[j]
時,意味著我們當前元素大於之前的一個元素,這兩個元素之間可以構成一個遞增子序列,所以說我們可能要進行更新dp[i],為什麼是可能呢?因為我們dp[i]
的值可能比dp[j]+1
(dp[j]+1的意思就是前j個元素構成的遞增序列,再加上num[i]這個值的長度)這個值更大,所以說我們得取一個最大的值。 -
因此,遞推公式為:
vector<int> dp(nums.size(),1);
int ans=1;
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
遍歷順序
- 由於dp[i]是要由它之前的元素dp[j]來推導的,因此遍歷順序明顯是從前向後遍歷
如何初始化?
- 首先,我們將dp[i]中的所有值全都初始化為1,因為每個元素至少都有一個遞增子序列(也就是它本身構成的子序列)
- 然後,依據我們的遞推公式從前向後進行初始化操作即可。
舉例驗證dp陣列
- nums陣列: [10,9,2,5,3,7,101,18]
- 以10結尾的最長上升子序為:[10]
- 以9為結尾的最長上升子序列為:[9]
- 以2為結尾的最長上升子序列為:[2]
- 以5為結尾的最長上升子序列為:[2,5]
- 以3為結尾的最長上升子序列為:[2,3]
- 以7為結尾的最長上升子序列為:[2,3,7]
- 以101為結尾的最長上升子序列為:[2,3,7,101]
- 以18為結尾的最長上升子序列為:[2,3,7,18]
- 這個例子也說明了我們的dp陣列是正確的
程式碼實現
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> dp(nums.size(),1);
//這個初始值為1,因為至少都有長度為1的遞增子序列
int ans=1;
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
return ans;
}
};