单调队列

1031 字
5 分钟
单调队列

概念#

什么是单调队列#

单调队列是一种特殊的双端队列,其中的元素保持单调递增或单调递减的顺序。

特点:

· 双端操作:可以在队首和队尾进行插入和删除 · 单调性:队列中的元素始终保持单调递增或递减 · 时间复杂度:每个元素最多入队一次、出队一次,均摊O(1)

单调队列解决的问题#

主要应用:

  1. 滑动窗口最值问题 - 经典应用
  2. 优化动态规划 - 减少状态转移的时间复杂度
  3. 滑动窗口最值问题模板

问题描述: 给定长度为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

注意事项总结#

  1. 存储下标:队列中存储元素下标而不是值,便于判断元素是否在窗口内
  2. 维护单调性: · 最小值:弹出所有>=当前元素的队尾 · 最大值:弹出所有<=当前元素的队尾
  3. 维护窗口大小:
    if (i - q.front() + 1 > k)
    q.pop_front();
  4. 输出时机:从第k个元素开始输出结果
  5. 时间复杂度:O(n),每个元素最多入队出队一次

常见变种与应用#

  1. 多维度滑动窗口:处理二维或更高维度的滑动窗口
  2. 带权重的滑动窗口:元素带有权重的最值问题
  3. 动态规划优化:如多重背包问题的单调队列优化

掌握单调队列的核心在于理解其”淘汰机制”:永远保留对后续窗口计算最有潜力的元素,淘汰那些永远不会成为答案的元素。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Profile Image of the Author
HandlerOne
おかえり
公告
本站已整理 138 篇技术笔记,并按 8 条主线排成学习路线(141 站);站内搜索与桌宠对话均已上线。
分类
标签
最新动态
站点统计
文章
138
分类
12
标签
42
总字数
597,044
站点信息
构建平台
腾讯云 · Nginx
博客版本
v6.16.8
文章目录