[python刷题模板] 单调队列

一、 算法&数据结构

1. 描述

单调队列通常用来维护窗口移动、扩展过程中,当前窗口最大/最小值的问题。

2. 复杂度分析

  1. 队列的复杂度最坏是, O(n),但是平均来说是O(1)
  2. 当我们需要对数组中每个元素都搜一遍的时候,那平均每次操作就是O(1)

3. 常见应用

  1. 窗口极值问题
  2. 背包优化

4. 常用优化

  1. python中的队列可以调用collections.deque
  2. 创建:q = deque()
  3. 询问队列是否非空:if q:
  4. 队尾入队: q.append()
  5. 队尾出队: q.pop()
  6. 队首入队: q.appendleft()
  7. 队首出队: q.popleft()
  8. 询问队尾: q[-1]
  9. 询问队首: q[0]

二、 模板代码

1. 询问滑窗最大值

例题: 239. 滑动窗口最大值
单调队列经典滑窗。
维护一个单调递降队列,队首是答案,队尾判断是否弹出。
窗口滑动时,判断队尾比i小的全部弹出,因为他们对后边的窗口来说贡献不会大于i。
滑动后判断队首元素是否窗外,弹出后,队首就是答案。
参考: [LeetCode解题报告] 滑动窗口最大值

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        q = deque()
        for i in range(k):
            while q and nums[i]>=nums[q[-1]]:
                q.pop()
            q.append(i)
        # print(q)
        ans = []
        ans.append(nums[q[0]])
        for i in range(k,len(nums)):
            while q and nums[i]>=nums[q[-1]]:
                q.pop()
            q.append(i)
            if q[0] <= i-k:
                q.popleft()
            # print(i,q)
            ans.append(nums[q[0]])
        return ans

2. 询问向右膨胀的窗最大值

链接: 1499. 满足不等式的最大值
和上一题比,它窗口的左端点看似是不变的,但是加了个限制条件xj-xi<=k(x有序),其实是用这个条件弹出队首。
因此维护单调递降队列,令j>i,则yi + yj + |xi - xj|转化为(yi-xi)+(yj+xj),扫描每个j,队列存y-x的值
参考: [LeetCode解题报告] 1499. 满足不等式的最大值

class Solution:
    def findMaxValueOfEquation(self, points: List[List[int]], k: int) -> int:        
        ans = -1e9
        q = deque()
        x,y = points[0]
        q.append((y-x,x))
        for i in range(1,len(points)):
            x,y = points[i]
            while q and x - q[0][1] > k:
                q.popleft()

            if q:
                ans = max(ans,q[0][0] + x + y)   
            while q and q[-1][0] <= y-x:                        
                q.pop()              

            q.append((y-x,x))
        
        return ans

三、其他

  1. 单调队列和单调栈是强力优化,就是不容易想到。

四、更多例题

  • 待补充

五、参考链接

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值