【區間 dp】A006_LC_帶限制的子序列和(dp / 單調隊列優化)

一、Problem

Given an integer array nums and an integer k, return the maximum sum of a non-empty subsequence of that array such that for every two consecutive integers in the subsequence, nums[i] and nums[j], where i < j, the condition j - i <= k is satisfied.

A subsequence of an array is obtained by deleting some number of elements (can be zero) from the array, leaving the remaining elements in their original order.

Input: nums = [10,2,-10,5,20], k = 2
Output: 37
Explanation: The subsequence is [10, 2, 5, 20].

Constraints:

1<=k<=nums.length<=1051 <= k <= nums.length <= 10^5
104<=nums[i]<=104-10^4 <= nums[i] <= 10^4

二、Solution

方法一:dp(超時)

  • 定義狀態
    • dp[i]dp[i] 表示以 ii 結尾的最大子序列和
  • 思考初始化:
    • dp[i]=A[i]dp[i] = A[i] 表示最短的子序列和爲自己
  • 思考狀態轉移方程
    • dp[i]=max(dp[i], dp[j]+A[i])0/ikj<i)dp[i] = max(dp[i],\ dp[j] + A[i])( 0/i-k \leqslant j <i),MSS 要麼是以 i 結尾,要麼是以區間 [ik,i)[i-k, i) 中任意一個數結尾,且選上 A[i]A[i]
  • 思考輸出maxdp[0...i]maxdp[0...i]

預期是超時的,但還是提交了一發…

class Solution {
    public int constrainedSubsetSum(int[] A, int k) {
        int n = A.length, dp[] = new int[n+5], max = A[0];
        for (int i = 0; i < n; i++) 
            dp[i] = A[i];
        for (int i = 1; i < n; i++)
        for (int j = Math.max(0, i-k); j < i; j++) {
            dp[i] = Math.max(dp[i], dp[j] + A[i]);
            max = Math.max(max, dp[i]); 
        }
        return max;
    }
}

複雜度分析

  • 時間複雜度:O(n2)O(n^2)
  • 空間複雜度:O(n)O(n)

方法二:單調隊列優化

比賽時我還不知道單調隊列這個事,要不讓可以輕鬆拿下。由上可得 dp 方程爲:
dp[i]=max(dp[i],dp[ik...j]+A[i])dp[i] = max(dp[i], dp[i-k...j] + A[i])

中間求區間 [ik,i][i-k, i] 最大值這一步可用單調隊列優化掉…

class Solution {
    public int constrainedSubsetSum(int[] A, int k) {
        int n = A.length, dp[] = new int[n+5], max = A[0];
        for (int i = 0; i < n; i++) 
            dp[i] = A[i];
        int hh = 0, tt = 0, q[] = new int[(int) 1e5+5];
        q[++tt] = 0;
        
        for (int i = 1; i < n; i++) {
            while (hh <= tt && q[hh] < i-k) 
                hh++;
            dp[i] = Math.max(dp[i], dp[q[hh]] + A[i]);
            max = Math.max(max, dp[i]);
            while (hh <= tt && dp[q[tt]] < dp[i])
                tt--;
            q[++tt] = i;
        }
        return max;
    }
}

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章