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

LeetCode 2762: Continuous Subarrays

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

基本資料
#

難易度: medium 第一次嘗試:2026-01-19

  • 提交紀錄:Accepted(一次通過)

解題思路
#

子陣列中任兩個數的差都不超過 2,等於 max - min <= 2。

這個條件有單調性:一個子陣列合法,它的任何子陣列也合法。所以用滑動窗口:右端每往右一格,就把左端往右推到窗口重新合法為止。以 right 結尾的合法子陣列有 right - left + 1 個。

問題是要隨時知道窗口的最大值和最小值。用 heap 可以做到 O(log n),但用兩個單調隊列可以做到均攤 O(1):

  • max_q:存 index,對應的值遞減,隊首就是窗口最大值。
  • min_q:存 index,對應的值遞增,隊首就是窗口最小值。

LeetCode 把這題標成 heap,但單調隊列更快也更簡單。

我的解法
#

from collections import deque

class Solution:
    def continuousSubarrays(self, nums: List[int]) -> int:
        max_q, min_q = deque(), deque()
        left = count = 0
        for right, x in enumerate(nums):
            while max_q and nums[max_q[-1]] < x:
                max_q.pop()
            max_q.append(right)
            while min_q and nums[min_q[-1]] > x:
                min_q.pop()
            min_q.append(right)

            while nums[max_q[0]] - nums[min_q[0]] > 2:
                if max_q[0] == left:
                    max_q.popleft()
                if min_q[0] == left:
                    min_q.popleft()
                left += 1

            count += right - left + 1
        return count

left 往右移時,只有剛好等於 left 的隊首需要移除;其他元素的 index 都比 left 大,還在窗口裡。

複雜度
#

時間 O(n):每個 index 最多進出每個隊列各一次。空間 O(n)。

要特別避免的錯誤
#

  • 每次都對窗口取 max() 和 min():O(n^2)。
  • 單調隊列存值而不是 index:沒辦法判斷隊首是不是已經離開窗口。
  • 計數用 +1 而不是 + (right - left + 1):要數的是所有以 right 結尾的子陣列。

面試口說整理
#

條件等價於窗口最大值減最小值不超過 2,而且合法子陣列的子陣列也合法,所以用滑動窗口。我維護兩個存 index 的單調隊列,一個遞減、一個遞增,隊首分別是窗口最大值和最小值。右端每加入一個數,就把左端推到窗口合法為止,再加上以 right 結尾的子陣列數 right - left + 1。每個 index 進出隊列各一次,時間 O(n)。

相關文章

LeetCode 2962: Count Subarrays Where Max Element Appears at Least K Times
·1 分鐘
LeetCode Medium Sliding-Window Array
LeetCode 2962 解題筆記:「至少 k 次」的計數視窗:最大值出現 k 次時一直縮左邊,縮完後左端在 [0, left) 的子陣列都合法,count += left
LeetCode 1040: Moving Stones Until Consecutive II
·1 分鐘
LeetCode Medium Sliding-Window Math Sorting Array
LeetCode 1040 解題筆記:最多步數 = 總空位 − 第一步會浪費掉的那一邊空隙;最少步數用長度 n 的視窗找最多石頭,n - 1 顆已連續、剩一顆在遠處時要特判成 2
LeetCode 1234: Replace the Substring for Balanced String
·1 分鐘
LeetCode Medium Sliding-Window String
LeetCode 1234 解題筆記:替換一段之後,視窗外的每個字元都不能超過 n / 4;用「求最短」的滑動視窗維護視窗外的數量
LeetCode 2555: Maximize Win From Two Segments
·1 分鐘
LeetCode Medium Sliding-Window Binary-Search Array
LeetCode 2555 解題筆記:滑動視窗算出以每個獎品結尾的一段能拿幾個;同時記錄「前 i 個獎品裡一段最多拿幾個」,第二段就接在第一段左邊
LeetCode 1838: Frequency of the Most Frequent Element
·1 分鐘
LeetCode Medium Sliding-Window Sorting Greedy Prefix-Sum Binary-Search Array
LeetCode 1838 解題筆記:排序後,把視窗裡的數都加到 nums[right] 的花費是 nums[right] × 長度 − 視窗總和;花費 > k 就縮左邊
LeetCode 2271: Maximum White Tiles Covered by a Carpet
·1 分鐘
LeetCode Medium Sliding-Window Greedy Sorting Prefix-Sum Binary-Search Array
LeetCode 2271 解題筆記:地毯的左端放在某段白磚的起點一定不會更差;排序後用雙指針,完整蓋住的段累加,最後一段只算部分