[python刷题模板] 单调队列
一、 算法&数据结构
1. 描述
单调队列通常用来维护窗口移动、扩展过程中,当前窗口最大/最小值的问题。
2. 复杂度分析
- 队列的复杂度最坏是, O(n),但是平均来说是O(1)
- 当我们需要对数组中每个元素都搜一遍的时候,那平均每次操作就是O(1)
3. 常见应用
- 窗口极值问题
- 背包优化
4. 常用优化
- python中的队列可以调用collections.deque
- 创建:q = deque()
- 询问队列是否非空:if q:
- 队尾入队: q.append()
- 队尾出队: q.pop()
- 队首入队: q.appendleft()
- 队首出队: q.popleft()
- 询问队尾: q[-1]
- 询问队首: 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
三、其他
- 单调队列和单调栈是强力优化,就是不容易想到。
四、更多例题
- 待补充