最長上升子序列和

最長上升子序列長度

題意:給定一個無序的整數數組,找到其中最長上升子序列的長度。

輸入: [10,9,2,5,3,7,101,18]
輸出: 4 
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4

解法:這是一道經典的動態規劃
狀態表示:dp[i]表示序列前i個數(必須包含nums[i])的最長上升子序列長度
狀態轉移:dp[i] = max(dp[j] + 1), 0<=j<i && nums[j]<nums[i]
程序(CPP)

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int res = 0;
        for(int i = 0; i < n; i++)
        {
            dp[i] = 1;
            for(int j = 0; j < i; j++)
                if(nums[j] < nums[i]) 
                    dp[i] = max(dp[i], dp[j] + 1);
            res = max(res, dp[i]);
        }
        return res;
    }
};

帶限制的子序列和

題意:給你一個整數數組 nums 和一個整數 k ,請你返回 非空 子序列元素和的最大值,子序列需要滿足:子序列中每兩個 相鄰 的整數 nums[i] 和 nums[j] ,它們在原數組中的下標 i 和 j 滿足 i < j 且 j - i <= k 。
數組的子序列定義爲:將數組中的若干個數字刪除(可以刪除 0 個數字),剩下的數字按照原本的順序排布。

輸入:nums = [10,-2,-10,-5,20], k = 2
輸出:23
解釋:子序列爲 [10, -2, -5, 20]

思路:與最長上升子序列問題一樣
狀態表示:dp[i]表示序列前i個數(必須包含nums[i])的帶限制的子序列和最大值
狀態轉移:dp[i] = nums[i] + max(dp[j]), i-k<=j<i
樸素解法如下:

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int constrainedSubsetSum(vector<int>& nums, int k) {
        int n = nums.size();
        int res = nums[0];
        for(int i = 0; i < n; i++)
        {
            dp[i] = nums[i];
            for(int j = max(0, i - k); j < i; j++)
                dp[i] = max(dp[i], dp[j] + nums[i]);
            res = max(res, dp[i]);
        }
        return res;
    }
};

高級解法:狀態轉移方程爲dp[i] = nums[i] + max(dp[j]), i-k<=j<i,暴力解法每次求max(dp[j]), i-k<=j<i都要遍歷k個數,時間複雜度爲O(nk)O(nk)。我們可以用優先隊列維護max(dp[j]) i-k<=j<i,時間複雜度將爲O(nlogk)O(nlogk),程序如下:

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int constrainedSubsetSum(vector<int>& nums, int k) {
        // 優先隊列隊首元素爲{max(dp[j]), 對應最大dp[j]的下標}
        priority_queue<pair<int, int>> q;
        int n = nums.size();
        int res = nums[0];
        for(int i = 0; i < n; i++)
        {
            dp[i] = nums[i];
            // 下標與i距離超過k的以後永遠不會用到,出隊即可
            while(!q.empty() && i-q.top().second > k) q.pop();
            if(!q.empty()) dp[i] = max(dp[i], q.top().first + nums[i]);
            q.push({dp[i], i});
            res = max(res, dp[i]);
        }
        return res;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章