单调队列

基本内容

一种维护数组窗口最大值或者最小值的方法

题目要求:依次输出在数组中以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也不可能是最大值。
  • 其他注意事项
  • 用数组存储窗口的效率不如双端队列,因为有删除第一个元素的操作;

  • 窗口内存储索引的效率往往会比存储元素值的效率要高,不同存储方式判断窗口是否满了的方式不同;

题目

  1. Leetcode 918. 环形子数组的最大和

    该题目前采用动态规划的变形解决

  2. 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
    
  3. 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]
    
posted @ 2024-10-27 22:06  九年义务漏网鲨鱼  阅读(29)  评论(0)    收藏  举报