↓快轉到主要內容
  1. LeetCode/

LeetCode 1425: Constrained Subsequence Sum

·1 分鐘· ·
LeetCode Hard Sliding-Window Dynamic-Programming Monotonic-Queue Heap Queue Array
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-09-10

  • 提交紀錄:Time Limit Exceeded → Accepted ×2

解題思路
#

dp[i] = 以 nums[i] 結尾的子序列最大和。前一個元素必須在 [i - k, i - 1] 裡,或者 nums[i] 自己開頭:

dp[i] = nums[i] + max(0, max(dp[i-k], ..., dp[i-1]))

直接算是 O(nk)。max(dp[i-k..i-1]) 就是一個長度 k 的滑動視窗最大值,用單調佇列(存 index,dp 值遞減):

  1. 頭端的 index < i - k 就丟掉(過期)。
  2. 頭端就是視窗最大值,> 0 才接上去。
  3. 尾端 dp 值 <= dp[i] 的都丟掉(被支配),再放入 i。

答案是 max(dp)(子序列不能是空的)。

我的嘗試
#

第一版想用貪心一段一段往前跳,每段挑一個數接過去。迴圈最後寫成 i = j,但 j 是這一段的最後一個位置,走到最後一段(或 k = 1)時 j == i,i 不會前進,迴圈停不下來,TLE。之後改成上面的 DP + 單調佇列 AC。

正確解法
#

from collections import deque

class Solution:
    def constrainedSubsetSum(self, nums: List[int], k: int) -> int:
        dp = nums[:]
        dq = deque()                               # index,dp 值遞減
        for i in range(len(nums)):
            if dq and dq[0] < i - k:
                dq.popleft()                       # 過期
            if dq and dp[dq[0]] > 0:
                dp[i] += dp[dq[0]]                 # 接在最好的前一個後面
            while dq and dp[dq[-1]] <= dp[i]:
                dq.pop()                           # 被 dp[i] 支配
            dq.append(i)
        return max(dp)

我原本直接寫 dp = nums,會改到輸入陣列;這裡用 nums[:] 複製一份。

複雜度
#

時間 O(n),空間 O(n)。

要特別避免的錯誤
#

  • O(nk) 直接取前 k 個的最大值:n、k 都到 10^5。
  • 前一個的最大值是負的時候,不要接上去,自己開頭比較好。
  • 答案是 max(dp),不是 dp[-1]。

面試口說整理
#

dp[i] 是以 nums[i] 結尾的最大和,等於 nums[i] 加上前 k 個 dp 的最大值,如果那個最大值是負的就不接。前 k 個的最大值是滑動視窗最大值,我用單調佇列維護:頭端丟過期的、尾端丟被新值支配的,頭端就是最大值。每個 index 進出一次,時間 O(n)。

相關文章

LeetCode 3835: Count Subarrays With Cost Less Than or Equal to K
·1 分鐘
LeetCode Medium Sliding-Window Monotonic-Queue Queue Array
LeetCode 3835 解題筆記:花費 = (最大 - 最小) × 長度,視窗變大只會變貴,所以可以滑動視窗數子陣列;視窗最大、最小值用兩個單調佇列維護
LeetCode 1696: Jump Game VI
·2 分鐘
LeetCode Medium Dynamic-Programming Monotonic-Queue Queue Heap
LeetCode 1696 解題筆記:dp[i] = nums[i] + 前 k 個 dp 的最大值;前 k 個的最大值用單調佇列維護,O(n)
LeetCode 2163: Minimum Difference in Sums After Removal of Elements
·2 分鐘
LeetCode Hard Dynamic-Programming Heap Array
LeetCode 2163 解題筆記:枚舉第一段和第二段的分界 k;左邊 nums[:k] 選 n 個最小的(最大堆維護),右邊 nums[k:] 選 n 個最大的(最小堆維護),前後綴各掃一次
LeetCode 1235: Maximum Profit in Job Scheduling
·1 分鐘
LeetCode Hard Dynamic-Programming Binary-Search Sorting Array
LeetCode 1235 解題筆記:工作依結束時間排序,best[j] = 只用前 j 個工作的最大收益;選第 j 個時二分搜尋最後一個結束時間 <= 開始時間的工作
LeetCode 1335: Minimum Difficulty of a Job Schedule
·1 分鐘
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 1335 解題筆記:切成 d 段的分割 DP;dp(i, k) = 從第 i 個工作開始、剩 k 天的最小難度,枚舉今天做到哪裡,邊枚舉邊更新今天的最大難度
LeetCode 312: Burst Balloons
·1 分鐘
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 312 解題筆記:枚舉區間 (i, j) 裡「最後一個」戳破的氣球 k,這時它的鄰居就是 i 和 j,左右兩邊的子問題互相獨立