1. 程式人生 > 其它 >LeetCode/最大遞增子序列

LeetCode/最大遞增子序列

給你一個整數陣列 nums ,找到其中最長嚴格遞增子序列的長度。

1. 動態規劃

dp[i]表示以i結尾的最長長度
狀態轉移方程dp[i] = max(dp[j])+1 if num[j]<num[i]
邊界條件 dp[0] = 1
時間複雜度為O(n2),即遍歷一遍,同時對每個元素往前搜尋一遍

動態規劃
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        //動態規劃
        int n = nums.size();
        if(n==0) return 0;
        vector<int> dp(n); //dp[i]表示以i結尾的最長長度
        int res = 0;
        for(int i=0;i<n;i++){
            int max_ = 0;
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]) max_=max(max_,dp[j]);
            }
            dp[i]= max_+1;
            res = max(res,dp[i]);
        }
        return res;
    }
};

2. 動態規劃優化

注意到方法一反向搜尋時,要找的是序列末位元素小於當前元素的最大序列長度
我們關心的只是某一序列長度的最小末尾元素,所以dp[i]可以表示為序列長度為i的最小末尾元素值
這樣不僅能減少查詢的資料量,還能使用二分法進行查詢

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        //動態規劃
        int n = nums.size();
        if(n==0) return 0;
        vector<int> dp(n); //dp[i]記錄i長度序列的最後元素值
        int res = 0;
        for(int k=0;k<n;k++){
           int i =0;int j =res;//res 為當前最長長度
           while(i<j){
               int m = (i+j)/2;
               if(dp[m]<nums[k]) i=m+1;//移動左邊界,最終移到恰滿足條件的下一位置
               else j=m; //移動右邊界
           }
           dp[i] = nums[k];//把該元素作為最小元素替換下一序列長度
            if(j==res) res++;//如果該位置拓寬了最大長度,最大長度更新
        }
        return res;
    }
};