单调递减队列保存候选下标,过期从队首删,较小候选从队尾删,O(n)。
OJ: leetcodecn
题目 ID: sliding-window-maximum
难度:提高+/省选-
标签:队列单调队列滑动窗口数组cpppython
日期: 2026-07-28 22:05
题意
给定数组和滑动窗口大小 k,返回每个窗口的最大值。
思路
暴力 O(nk) 每个窗口扫一遍最大值。优化:用单调递减队列保存窗口内可能成为最大值的元素下标。
- 队首始终是当前窗口的最大值。
- 新元素入队时,从队尾弹出所有比它小的元素(它们再也不可能成为最大值)。
- 队首超出窗口范围时弹出。
每个元素至多入队出队一次,均摊 O(n)。
代码
cpp
/**
* Author by Rainboy
*/
// main.cpp:单调递减队列,O(n)。
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
vector<int> maxSlidingWindow(vector<int> &nums, int k) {
deque<int> q;
vector<int> ans;
for (int i = 0; i < (int)nums.size(); i++) {
while (!q.empty() && q.front() <= i - k)
q.pop_front();
while (!q.empty() && nums[q.back()] <= nums[i])
q.pop_back();
q.push_back(i);
if (i >= k - 1)
ans.push_back(nums[q.front()]);
}
return ans;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<int> a(n);
for (int &x : a)
cin >> x;
auto v = Solution().maxSlidingWindow(a, k);
for (int x : v)
cout << x << ' ';
return 0;
}python
#!/usr/bin/env python3
from typing import List
from collections import deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
q = deque()
ans = []
for i, x in enumerate(nums):
while q and q[0] <= i - k:
q.popleft()
while q and nums[q[-1]] <= x:
q.pop()
q.append(i)
if i >= k - 1:
ans.append(nums[q[0]])
return ans
def main() -> None:
n, k = map(int, input().split())
nums = list(map(int, input().split()))
print(*Solution().maxSlidingWindow(nums, k))
if __name__ == "__main__":
main()复杂度
- 时间复杂度:O(n),每个元素入队出队各一次。
- 空间复杂度:O(k),队列最多存 k 个元素。
总结
单调队列适用于"滑动窗口最值"问题,"被更大值淘汰"的永久性是保证 O(n) 的关键。该模型与单调栈对称:栈处理的是固定端点向一侧扩展,队列处理的是连续滑动窗口。