栈
先进后出;
基本操作:
#include<iostream>
using namespace std;
const int N=100010;
int stk[N],tt;
//插入
stk[++tt]=x;
//弹出
tt--;
//判断栈是否为空
if(tt>0) not empty
else empty;
//栈顶
stk[tt];
单调栈常见模型
找出每个数左边离它最近的比它大/小的数
int tt=0;
for(int i=1;i<=n;i++)
{
while(tt&&check(q[tt],i)) tt–;
stk[++tt]=i;
}
应用:单调栈
首先考虑暴力的求解方法,即用双指针来进行求解,最终把结果进行输出。用单调栈进行优化:用栈来存储已经遍历过的数。然后分析哪一些数永远不会作为答案进行输出,例如求取距离最小且小于的数,则存在逆序的话则第一点会被删掉。则最终栈中存放的就是单调的序列,是一个单调增的序列,当输入ai时,则在栈中找小于的数即可。
#include<iostream>
using namespace std;
const int N=100010;
int n;
int stk[N],tt;
int main(){
cin>>n;
for(int i=0;i<n;i++){
int x;
cin>>x;
while(tt&&stk[tt]>=x) tt--;//栈不是空的,并且栈顶的元素是小于x的时候结束循环
if(tt) cout<<stk[tt]<<endl;
else cout<<-1<<endl;
stk[++tt]==x;
}
return 0;
}
队列
先进先出
//对列
//在队尾插入元素,在队头弹出元素
int q[N],hh,tt=-1;
//插入
q[++tt]=x;
//弹出
hh++
//
if(hh<=tt) not empty
else empty;
//队头元素
q[hh];
//取队尾元素
q[tt];
单调队列常见模型
常见问题:找到滑动窗口中的最大值最小值
int hh=0,tt=-1;
for(int i=0;i<n;i++)
{
while(hh<=tt&&check_out(q[hh])) hh++;//判断队头是否滑出窗口
while(hh<=tt&&check(q[tt],i)) tt–;
q[++tt]=i;
}
应用:滑动窗口的最大值最小值
仍然是具有单调性,开一个数组来保存距离矩阵左端点的距离,实现保证点一直在区间的内部。所以在将数加入队列的时候,存入的一定是比队列的队尾大的数,
是一个单调递增的单调队列。然后输出队列的头即可。
简单描述就是:在队列中存储的是一个单调递增的数列,然后还要再开一个数组来记录当前数字与区间端点的距离,以保证该点仍然在滑动窗口内,最终将队列的head输出就是答案。
#include<iostream>
using namespace std;
const int N=1000010;
int n,k;
int a[N],q[N];
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int hh=0,tt=-1;
for(int i=0;i<n;i++){
//判断队列是否已经滑出窗口
if(hh<=tt&&i-k+1>q[hh]) hh++;//a中存放的是数值的大小,在队列q中存放的是下标;
while(hh<=tt&&a[q[tt]]>=a[i]) tt--;
q[++tt]=i;
if(i>=k-1) printf("%d",a[q[hh]]);
//首先要保证队列不可以滑出窗口i-k+1>q[hh],即q[hh]是不断变大的,
//然后维护队列为单调递增序列
//都是最后记得把数添加到队列
}
return 0;
}