一.单调队列.
一.单调队列的介绍
单调队列 是 队列中元素之间的关系具有单调性,队列中的元素始终保持着单增或者单减的特性,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作,本质是有双端队列deque实现的。
特点:在每次加入或者删除元素时都保持序列里的元素有序,即队首元素始终是最小值或者最大值。
二.单调队列和优先队列的区别
优先队列
- 定义
对于堆(使用PriorityQueue实现):从队头到队尾按从小到大排就是最小堆(小顶堆),
从队头到队尾按从大到小排就是最大堆(大顶堆)—>队头元素相当于堆的根节点。
区别
- 单调队列是队列中的元素具有单调性,队列中元素始终保持单调增或单调减的特性。而优先队列中都元素不具有单调性,其是根据堆的特性实现的,保证队头是最大或者最小。
- 两者在STL中的操作也不同,单调队列用双向队列 deque 实现,而优先队列通过 PriorityQueue 实现。
三.单调队列出队,入队过程模拟
我们依次加入5个元素,分别为5,8,2,4,1
那么我们假设队列是单减的,那么队首元素始终是最大的,五次操作详细过程如下:
1.首先队列里面没有元素,5加进去。
2.第二个元素8大于队尾的元素,所以5要弹出去,8加进去。保持队首最大
3.第三个元素2小于队尾元素8,可以加进去,变为8 2
4.4大于队尾元素2,2弹出,4小于8,8不弹出,4加进去
5.1小于队尾元素4,1加进去,最后队列为8 4 1
二.滑动窗口 /【模板】单调队列
https://www.luogu.com.cn/problem/P1886
本单调队列的模版题,还将通过数组模拟和STL两种方式完成。
数组模拟
#include<bits/stdc++.h>
using namespace std;
#define MAX 1000005
#define ll long long //宏定义ll为long long
ll queuel[MAX],a[MAX]; //数组queue来模拟队列
int head=0,tail=-1; //head为头指针,tail为尾指针
int main()
{
int n,k;
cin>>n>>k; //单调增的单调队列
for(int i=1;i<=n;i++)
{
cin>>a[i];
while(head<=tail&&a[queuel[tail]]>=a[i]) //如果队列不为空并且队尾大于当前元素
tail--; //从尾部删除队尾元素
queuel[++tail]=i; //从队尾入队,(当前元素的下标)
while(head<=tail&&queuel[head]<=i-k) //如果滑动窗口超过该队头在数列在的位置
head++; //将队头从首部删除
if(i>=k)
cout<<a[queuel[head]]<<" "; //输出队头元素及该窗口期的最小元素
}
head=0,tail=-1; //注意,这里要将队列清空
cout<<endl;
for(int i=1;i<=n;i++) //单调减的单调队列
{
while(head<=tail&&a[queuel[tail]]<=a[i]) //下面的操作同理
tail--;
queuel[++tail]=i;
while(head<=tail&&queuel[head]<=i-k)
head++;
if(i>=k)
cout<<a[queuel[head]]<<" "; //输出队头元素及该窗口期的最大元素
}
cout<<endl;
return 0;
}
STL
#include<bits/stdc++.h>
using namespace std;
#define MAX 1000005
deque<int>q; //双向队列q(可以任意在队首和队尾增删元素)
int a[MAX];
int main() //其主要思路和模拟数组中差不多,注意区别是队列操作
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) //单调增的单调队列
{
cin>>a[i];
while(!q.empty()&&a[q.back()]>=a[i]) //如果不为空,并且队尾元素大于当前元素
q.pop_back(); //从队尾出队
q.push_back(i); //从队尾入队
if(i>=k)
{
while(q.front()<=i-k) //如果滑动窗口超过该队头在数列在的位置
q.pop_front(); //队首出队
cout<<a[q.front()]<<" ";
}
}
cout<<endl;
q.clear(); //清空队列
for(int i=1;i<=n;i++) //单调减的单调队列
{
while(!q.empty()&&a[q.back()]<=a[i])
q.pop_back();
q.push_back(i);
if(i>=k)
{
while(q.front()<=i-k) //同上
q.pop_front();
cout<<a[q.front()]<<" ";
}
}
return 0;
}
今天的就到这里了!~QVQ~