单调队列
1031 字
5 分钟
单调队列
概念
什么是单调队列
单调队列是一种特殊的双端队列,其中的元素保持单调递增或单调递减的顺序。
特点:
· 双端操作:可以在队首和队尾进行插入和删除 · 单调性:队列中的元素始终保持单调递增或递减 · 时间复杂度:每个元素最多入队一次、出队一次,均摊O(1)
单调队列解决的问题
主要应用:
- 滑动窗口最值问题 - 经典应用
- 优化动态规划 - 减少状态转移的时间复杂度
- 滑动窗口最值问题模板
问题描述: 给定长度为n的序列a,窗口大小为k,窗口从左向右滑动,求每个窗口位置的最小值和最大值。
滑动窗口最值问题模板
问题描述: 给定长度为n的序列a,窗口大小k,窗口从左向右滑动,求每个窗口位置的最小值和最大值
求最小值(单调递增队列)
// 维护单调递增队列for i from 1 to n: while 队列非空且队尾元素 >= a[i]: 弹出队尾 将i加入队尾 while 队首元素不在当前窗口内: 弹出队首 if i >= k: 输出队首元素作为当前窗口最小值求最大值(单调递减队列)
// 维护单调递减队列for i from 1 to n: while 队列非空且队尾元素 <= a[i]: 弹出队尾 将i加入队尾 while 队首元素不在当前窗口内: 弹出队首 if i >= k: 输出队首元素作为当前窗口最大值完整代码实现
#include <iostream>#include <deque>using namespace std;
const int N = 1e6 + 10;int n, k;int a[N];
int main() { cin >> n >> k; for (int i = 1; i <= n; i++) cin >> a[i];
deque<int> q; // 存储下标
// 窗口内最小值 - 单调递增队列 for (int i = 1; i <= n; i++) { // 维护单调性:弹出所有大于等于当前元素的队尾元素 while (q.size() && a[q.back()] >= a[i]) q.pop_back();
q.push_back(i);
// 维护窗口大小:如果队首元素超出窗口范围,弹出 if (i - q.front() + 1 > k) q.pop_front();
// 输出结果:从第k个元素开始输出 if (i >= k) cout << a[q.front()] << " "; } cout << endl;
// 窗口内最大值 - 单调递减队列 q.clear(); for (int i = 1; i <= n; i++) { // 维护单调性:弹出所有小于等于当前元素的队尾元素 while (q.size() && a[q.back()] <= a[i]) q.pop_back();
q.push_back(i);
// 维护窗口大小 if (i - q.front() + 1 > k) q.pop_front();
// 输出结果 if (i >= k) cout << a[q.front()] << " "; } cout << endl;
return 0;}8 3 1 3 -1 -3 5 3 6 7
[1,3,-1.-3,5,3,6,7]求最小值过程(单调递增队列)窗口位置 队列状态(下标) 最小值[1 3 -1] [3] -1[3 -1 -3] [4] -3[-1 -3 5] [4] -3[-3 5 3] [4,6] -3[5 3 6] [6,7] 3[3 6 7] [7,8] 3
求最大值过程(单调递减队列)窗口位置 队列状态(下标) 最大值[1 3 -1] [2] 3[3 -1 -3] [2] 3[-1 -3 5] [5] 5[-3 5 3] [5] 5[5 3 6] [7] 6[3 6 7] [8] 7注意事项总结
- 存储下标:队列中存储元素下标而不是值,便于判断元素是否在窗口内
- 维护单调性: · 最小值:弹出所有>=当前元素的队尾 · 最大值:弹出所有<=当前元素的队尾
- 维护窗口大小:
if (i - q.front() + 1 > k)q.pop_front();
- 输出时机:从第k个元素开始输出结果
- 时间复杂度:O(n),每个元素最多入队出队一次
常见变种与应用
- 多维度滑动窗口:处理二维或更高维度的滑动窗口
- 带权重的滑动窗口:元素带有权重的最值问题
- 动态规划优化:如多重背包问题的单调队列优化
掌握单调队列的核心在于理解其”淘汰机制”:永远保留对后续窗口计算最有潜力的元素,淘汰那些永远不会成为答案的元素。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
单调栈
算法单调栈是一种特殊的栈结构,栈中的元素保持单调递增或单调递减的顺序
2
算法错题本
算法在一个圆形操场的四周摆放 $N$ 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 $2$ 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
3
数论
算法如果 $a$ 除以 $b$ 没有余数,那么 $a$ 就是 $b$ 的倍数,$b$ 就是 $a$ 的约数,记作 $b \mid a$。 约数,也称因数。
4
高精度
算法当数据的值特别大,超出各种基本数据类型的存储范围时,需要使用高精度算法来计算加减乘除。
5
分治
算法问题一分为二 —递归(DFS)-合并答案 时间优化:O(nn)-O(n log n)
随机文章随机推荐

