当前位置:网站首页>单调队列,洛谷P1886 滑动窗口
单调队列,洛谷P1886 滑动窗口
2022-07-28 05:19:00 【今天也要加油啊!!】
单调队列
我们都已经知道了队列是一种先进先出的结构,单调队列顾名思义就是一种递增或递减的队列。由于所用的元素各入队出队一次,所以它的时间复杂度是O(n)。
单调队列适用的范围
那么我们通常在什么情况下才会使用单调队列呢?
一般会在求一定范围内的最大值或最小值考虑单调队列,(当然线段树也可以在nlog(n)的时间内做到)
例题
下面我们以一个例题来讲解如何使用单调队列 洛谷P1886 滑动窗口 (点击可进入洛谷官网提交)。
题目大意:
有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
输入n,k,和序列a,其中n为序列a的大小,k为窗口大小。(1<=k<=n<=106)
输出每次窗口滑动的最大值和最小值。
读懂题目意思我们很快就能想出一个暴力破解的思路,每次都枚举一个大小为k的区间,然后比出最大值,但是这样时间复杂度会高达O(nm),妥妥的超时。
思路:
到了这里我们想是不是可以维护一个队列que(因为我们从前往后遍历a,满足先进先出的条件,考虑使用队列),que维护的内容为结构体,结构体的内容为元素的大小和下标,que.front()是对应窗口的最大值,我们遍历这个序列a,如果当前que的头部元素不在这个窗口所对应的范围内(即下标超界),那么就可以从que头部弹出该元素了(que.pop_front()),假设当前遍历到的元素a[i],如果a[i]>=que.back(),那么说明a[i]比que.back()更有资格成为当前窗口的最大值,所以可以抛弃尾部元素了(que.pop_back()),直到a[i]<que.back(),则将该元素加入que的尾部(que.push_back(a[i])),用while循环可以轻易实现这一步骤。到了这里我们就O(n)的时间内求出了所有的窗口最大值, 最小值也可以用同样的思路求出来,仔细观察一下que内部维护的值,我们发现它的元素的值满足单调递减的规律,所以它是一个单调队列。.
不多说了,直接上AC代码。
#include <iostream>
#include <queue>
#include <cstdio>
using namespace std;
const int maxn=2e6+286;
int st[2][2002000]; //用于存储答案
typedef struct node //定义结构体用于存储元素的下标和大小
{
int id,val; //下标、大小
};
node a[maxn]; //用于储存序列a
deque<node> que1,que2; //que1维护最大值,即单调递减的队列(头部元素是最大值)
//que2维护最小值,即单调递增的队列(头部元素是最小值)
int main()
{
int n,k;
int cnt=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) //读入序列a
{
scanf("%d",&a[i].val);
a[i].id=i;
}
for(int i=1;i<=n;i++) //遍历序列a
{
/* 如果a[i]>=que.back(),那么说明a[i]比que.back()更有资格成为当前窗口的最大值, 所以可以抛弃尾部元素了(que.pop_back()) */
while(!que1.empty()&&a[i].val>=que1.back().val)
que1.pop_back();
/* 如果a[i]<=que.back(),那么说明a[i]比que.back()更有资格成为当前窗口的最小值, 所以可以抛弃尾部元素了(que.pop_back()) */
while(!que2.empty()&&a[i].val<=que2.back().val)
que2.pop_back();
que1.push_back(a[i]); //将当前元素加入que
que2.push_back(a[i]);
while(i-k>=que1.front().id)
que1.pop_front(); //当前维护的头部元素不在窗口的范围内,即下标越界了,删除头部元素
while(i-k>=que2.front().id)
que2.pop_front();
if(i>=k) //存储答案
{
st[1][++cnt]=que1.front().val;
st[0][cnt]=que2.front().val;
}
}
//输出答案
for(int i=1;i<=cnt;i++)
printf("%d ",st[0][i]);
printf("\n");
for(int i=1;i<=cnt;i++)
printf("%d ",st[1][i]);
return 0;
}
希望在这里你能对单调队列有了进一步的了解,有所收获。
祝学习顺利!!!
边栏推荐
- CAD-GIS数据转换
- 树莓派蓝牙调试过程
- Openjudge: judge whether the string is palindrome
- The way of deep learning thermodynamic diagram visualization
- Collection of architectural design considerations
- 冶金物理化学复习 --- 液 - 液相反应动力学
- C语言回顾(指针篇)
- 【uni-app】uni-app中scroll-into-view的使用
- Review of metallurgical physical chemistry -- Fundamentals of chemical reaction kinetics
- 标准C语言学习总结7
猜你喜欢

冶金物理化学复习 --- 金属的电沉积,还原过程

GIS领域竞赛整理(不完全统计)

Sequence table OJ topic

Review of metallurgical physical chemistry -- cathodic polarization, overpotential, anode and anode process in metal electrodeposition

Review of Metallurgical Physical Chemistry - gas liquid phase reaction kinetics

结果填空 国庆有几天是星期日(纯Excel解决)

顺序表oj之合并两个有序数组

Idea configures the service (run dashboard) service, and multiple modules are started at the same time

对极大似然估计、梯度下降、线性回归、逻辑回归的理解

结果填空 购物单(教你用Excel解决)
随机推荐
curd组件中的时间设置
结果填空 国庆有几天是星期日(纯Excel解决)
Microsoft Edge浏览器插件(1)
Review of metallurgical physical chemistry ---- gas solid reaction kinetics
[MySQL] solve the problem of MySQL time zone and 8-hour difference in database time
Oracle create table, delete table, modify table (add field, modify field, delete field) statement summary
TopK问题
结果填空 星系炸弹(Excel秒杀)
Openjudge: count the number of numeric characters
标准C语言学习总结9
ES6--->箭头函数、类、模块化
Microsoft Edge浏览器插件(2)
The difference between get and post
DOM--事件链、事件冒泡和捕获、事件代理
标准C语言总结4
【博学谷学习记录】超强总结,用心分享 | 集合
DOM基础
ArrayList multithreading security solution
uni-app-双击事件模拟
五子棋优化版