单调队列学习笔记
前言
我们常说:“我又被单调队列了/kk”,意为“我比比自己小还比自己强的人吊打了”。
今天我们赖了解什么是“单调队列”。
分析
毫无疑问,最开始必定想到的是 的暴力。
代码不贴啦,必定 。
考虑优化。
要求的是每连续的 个数中的最大值,很明显,当一个数进入所要 "寻找" 最大值的范围中时,若这个数比其前面(先进队)的数要大,显然,前面的数会比这个数先出队且不再可能是最大值。
- 摘自 OI Wiki。
这是复杂度为 。
对于样例分析
1 3 -1 -3 5 3 6 7
操作 | 队列 |
---|---|
1 入队 |
{1} |
3 入队 |
{1,3} |
-1 入队,队内元素大于 -1 的出队 |
{-1} |
-3 入队,队内元素大于 -3 的出队 |
{-3} |
5 入队 |
{-3,5} |
3 入队,队内元素大于 3 的出队 |
{-3,3} |
6 入队,-3 不在窗内,出队。 |
{3,6} |
7 入队 |
{3,6,7} |
Code
- 摘自 OI Wiki。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxn 1000100
using namespace std;
int q[maxn], a[maxn];
int n, k;
void getmin() { //得到这个队列里的最小值,直接找到最后的就行了
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] >= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
void getmax() { //和上面同理
int head = 0, tail = 0;
for (int i = 1; i < k; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
}
for (int i = k; i <= n; i++) {
while (head <= tail && a[q[tail]] <= a[i]) tail--;
q[++tail] = i;
while (q[head] <= i - k) head++;
printf("%d ", a[q[head]]);
}
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
getmin();
printf("\n");
getmax();
printf("\n");
return 0;
}
//deque实现
#include <cstdio>
#include <queue> // 提供deque
#define MAXN 2000005
using namespace std;
struct Num{
int index,x;//需要记录单调队列内每个数的入队时间(index)和大小(x)
};
int a[MAXN]; //原数组
deque<Num> q; //单调队列
int main(void){
int n,m; //n表示序列长度,m表示滑动窗口长度
Num t;//保存当前元素
//输入
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
//问题解决
for (int i=1;i<=n;i++){
//先输出数a[i]前的最小值
if (q.empty()) //q空,即a[i]前没有元素
printf("0\n");
else { //否则判断队头是否需要出队并输出范围内的队头
if (q.front().index+m<i) //队头已经超出滑动窗口范围
q.pop_front(); // 弹出队头
printf("%d\n",q.front().x); //此时队一定非空(想想为什么)
}
while ((!q.empty()) && q.back().x>=a[i])
//当队列非空时,不断弹出队尾比当前元素大的元素
q.pop_back();
t.index=i;
t.x=a[i];
q.push_back(t);//将当前元素入队
//注意:当前元素无论如何都会入队(想想为什么)
}
return 0;
}
无耻求赞求关注(((q(≧▽≦q)
本文作者:int32
本文链接:https://www.cnblogs.com/lycqwq/articles/mono-queue-note.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】AI 的力量,开发者的翅膀:欢迎使用 AI 原生开发工具 TRAE
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
· AES 加密模式演进:从 ECB、CBC 到 GCM 的 C# 深度实践
· InnoDB为什么不用跳表,Redis为什么不用B+树?
· 记一次 C# 平台调用中因非托管 union 类型导致的内存访问越界
· [EF Core]聊聊“复合”属性
· 那些被推迟的 C# 14 特性及其背后的故事
· 博客园出海记-开篇:扬帆启航
· 微软开源的 MCP 教程「GitHub 热点速览」
· 记一次 .NET 某汽车控制焊接软件 卡死分析
· 关于布尔类型的变量不要加 is 前缀,被网友们吐槽了,特来完善下
· C#中的多级缓存架构设计与实现深度解析