給你一個整數陣列 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
-1e4 <= nums[i] <= 1e4
進階思考:
你能將演算法的時間複雜度降低到 O(n log(n)) 嗎? -->相關題目連結暫時
題解:
動態規劃的題
f[i]
狀態表示:
- 集合: 只考慮前 i 個數(包含i), 並且以第i個數結尾的子序列的所有方案
- 屬性: 最大值
狀態計算:
對於第 i 個數的狀態轉移方程是:
- 只有一個第 i 個數, 此時f[i] = 1;
- 以第1個數結尾的基礎上再選第i個數尾結尾, 以第2個數結尾的基礎上再選第i個數結尾...以第i - 1個數結尾的基礎上再選第i個數結尾,上面所有情況的長度取max就是f[i], 也就是 f[j] + 1, 因為選第i個數, 所有長度加1, j 屬於(0, i)
看不懂狀態計算的話, 一定要多理解狀態表示, 理解了狀態表示, 就可以理解狀態計算
ac程式碼👇
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if (nums.size() == 0) return 0;
// 以第i個數結尾的最長上升子序列 max
vector<int> f(nums.size(), 0);
for (int i = 0; i < nums.size(); i ++)
{
f[i] = 1; // 只有第i個數的情況, 也就是狀態計算1
for (int j = 0; j < i; j ++) // 狀態計算2
if (nums[i] > nums[j]) f[i] = max(f[i], f[j] + 1); // 要加上判斷, 使子序列滿足嚴格的單調遞增
}
int res = 0; // 最長上升子序列不一定會選最後一個, 也不一定會選倒數第二個..., 所有最後的答案是f陣列中的最大值, 主要還是要理解狀態表示
for (int i = 0; i < f.size(); i ++) res = max(res, f[i]);
return res;
}
};
覺得寫的不錯的話, 點個贊吧~