【学习笔记】单调队列
建议结合板题食用。
单调队列,顾名思义,就是队内元素满足单调性的队列,可以用于在线性的时间复杂度内求一个序列所有长度为
先看一下这个序列:
1 14 5 14 19 1 98 10
设这里的
首先,我们将
1 14
然后我们准备将
分类讨论一下:
当一个区间包含
当一个区间不包含
综上,
看到要从队尾弹出元素,显然要用双端队列(std::deque
)实现。
然后我们再把
1 5
此时发现入队元素达到了
然后再遍历到下一个
这个
5 14
此时队中的元素都是第二个区间的元素,区间最小值即为队头
依此模拟下去,即可求出所有区间最小值。
我们发现,单调队列题目的套路如下:
-
把队头所有“过期”的元素弹出。
-
发现一个新元素,将队尾破坏单调性的元素(例如上例的第一个
)弹出队尾,插入这个元素,保证队列元素的单调。 -
队头往往构成最优。
-
把当前元素入队。
简化一下:
把队头队尾不可能在未来构成最优的元素弹出,取队头为当前区间最优,并将当前元素入队。
由于每个元素入队一次,至多出队一次,所以总复杂度为
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 9;
int n,m;
int a[N];
deque<int>q1;
int main(){
scanf("%d%d", &n, &m);
for(int i = 1;i <= n;i++)
scanf("%d", &a[i]);
for(int i = 1;i <= n;i++){
while(!q1.empty() && q1.front() + m < i)
q1.pop_front();
while(!q1.empty() && a[q1.back()] >= a[i])
q1.pop_back();
if(i == 1)
printf("0\n");
else
printf("%d\n", a[q1.front()]);
q1.push_back(i);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)