单调队列
基本内容
一种维护数组窗口最大值或者最小值的方法
题目要求:依次输出在数组中以k为大小的滑动窗口的最大值
- 基本思想
在窗口大小上限为k的数组窗口中,始终保持该窗口的第一个值为该窗口的最大(小)值,并且窗口内的剩余值单调递减(递增)
- 核心代码解释

# 当i已经遍历到5
array = [1,3,-1,-3,5,3,6,7] #原数组
window = deque()
for i in range(len(array)):
if ... # 窗口是否已经满了的判断,如果满了,弹出第一个窗口
window.popleft()
while window and window[-1] < array[1]: # 5大于窗口内剩余元素,依次弹出,直到窗口为空
window.pop() #双端队列pop默认删掉最后一个
array.append(array[i]) # 加入5,此时5是最大的
# i遍历下一个元素3,窗口还未满且小于窗口内最后一个元素5,直接加入,因为如果5被弹出的话,3有可能是剩余窗口的最大值,所以需要保留了
# i遍历下一个元素4,窗口还未满但大于窗口内最后一个元素3,需要先把3弹出,因为即使5被弹出了,3也不可能是最大值。
- 其他注意事项
用数组存储窗口的效率不如双端队列,因为有删除第一个元素的操作;
窗口内存储索引的效率往往会比存储元素值的效率要高,不同存储方式判断窗口是否满了的方式不同;
题目
-
该题目前采用动态规划的变形解决
-
Leetcode 1438. 绝对差不超过限制的最长连续子数组
- 维护最大值和最小值,思路是对的,就差最后一步,将维护最大值和最小值的索引相减取最大值。
- 另一种解法:滑动窗口 + 有序集合 (平衡树)
- 类似的题目:
def longestSubarray(self, nums: List[int], limit: int) -> int: windowmax = deque() windowmin = deque() Vmax = 0 left = 0 for i in range(0, len(nums)): while windowmax and nums[i] < nums[windowmax[-1]]: windowmax.pop() while windowmin and nums[i] > nums[windowmin[-1]]: windowmin.pop() windowmax.append(i) windowmin.append(i) while windowmax and windowmin and (nums[windowmin[0]] - nums[windowmax[0]]) > limit: if nums[left] == nums[windowmax[0]]: windowmax.popleft() if nums[left] == nums[windowmin[0]]: windowmin.popleft() left += 1 Vmax = max(Vmax, i - left + 1) return Vmax -
Leetcode 3175. 找到连续赢 K 场比赛的第一位玩家
每日一题, 与单调队列相似,也可以看作是维护一个窗口的最大值
def findWinningPlayer(self, skills: List[int], k: int) -> int: window = deque() window.append(0) cnt = 0 for i in range(1,len(skills)): if window and skills[window[0]] < skills[i]: window.pop() window.append(i) cnt = 1 if cnt ==k : return window[0] else: cnt += 1 if cnt == k: return window[0] return window[0]

浙公网安备 33010602011771号