掌握单调队列算法,高效解决滑动窗口极值

单调队列的定义与特点

单调队列是一种特殊的队列数据结构,保证队列中的元素始终按照单调递增或递减的顺序排列。常用于解决滑动窗口类问题,能够高效维护区间极值。

单调队列的核心操作包括:

  • 入队时移除队尾破坏单调性的元素
  • 出队时检查队首元素是否过期
  • 始终保证队列头部是当前窗口的最值

实现单调队列的基本模板

class MonotonicQueue:
    def __init__(self):
        self.q = collections.deque()
    
    def push(self, x):
        while self.q and self.q[-1] < x:  # 维护单调递减
            self.q.pop()
        self.q.append(x)
    
    def max(self):
        return self.q[0]
    
    def pop(self, x):
        if self.q and self.q[0] == x:
            self.q.popleft()

典型应用场景:滑动窗口最大值

给定数组和窗口大小k,返回每个窗口的最大值:

def maxSlidingWindow(nums, k):
    q = MonotonicQueue()
    res = []
    for i, num in enumerate(nums):
        if i >= k:
            q.pop(nums[i - k])  # 移除离开窗口的元素
        q.push(num)
        if i >= k - 1:
            res.append(q.max())
    return res

时间复杂度优化至O(n),相比暴力解法O(nk)有显著提升。

算法优化技巧

处理边界条件时需注意:

  • 队列存储元素下标而非值,便于判断是否超出窗口范围
  • 初始化时先处理前k-1个元素
  • 结果收集从第k个元素开始

改进后的实现:

def maxSlidingWindow(nums, k):
    q = collections.deque()
    res = []
    for i in range(len(nums)):
        while q and nums[q[-1]] <= nums[i]:
            q.pop()
        q.append(i)
        if q[0] == i - k:
            q.popleft()
        if i >= k - 1:
            res.append(nums[q[0]])
    return res

扩展应用场景

单调队列还可用于解决:

  • 满足条件的子数组个数统计
  • 带限制的子序列和问题
  • 二维滑动窗口极值问题
  • 某些动态规划优化问题

例如求滑动窗口最小值只需修改比较条件:

while q and nums[q[-1]] >= nums[i]:  # 改为维护单调递增
    q.pop()

复杂度分析与比较

  • 空间复杂度:O(k)的额外空间
  • 时间复杂度:每个元素最多入队出队一次,O(n)
  • 相比堆结构:获取最值O(1) vs O(logk)
  • 相比线段树:实现更简单且常数更小

常见错误与调试建议

容易出现的问题包括:

  • 窗口移动时未正确移除过期元素
  • 比较条件写反导致单调性错误
  • 存储下标但比较时忘记取实际值
  • 初始化阶段过早开始收集结果

调试时可打印每个步骤的队列状态,验证:

  1. 队列是否始终保持单调性
  2. 队首元素是否始终在窗口范围内
  3. 结果收集时机是否正确
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值