【区间 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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章