leetcode力扣 300. 最長遞增子序列

小程xy發表於2024-05-26

給你一個整數陣列 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 個數的狀態轉移方程是:

  1. 只有一個第 i 個數, 此時f[i] = 1;
  2. 以第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;
    }
};

覺得寫的不錯的話, 點個贊吧~

相關文章