用数组模拟栈、模拟队列、单调栈以及单调队列

模拟栈,栈是先进后出,只有一个头因此只用一个tt可以记录当前位置

ll st[N],tt;

void push(int x) {//向栈顶插入一个数x

       tt++;

       st[tt]=x;

}

int pop(){//从栈顶弹出一个数

       return st[tt--];

}

int empty(){//判断栈顶是否为空

       return tt<=0;

}

int query(){//查询栈顶元素

       return st[tt];

}

例题:AcWing828

代码:

这里只写主函数,用到的函数都在上面了

int main(){

       ll m;

       cin>>m;

       while(m--){

              string str;

              cin>>str;

              if(str=="push"){

                     int x;

                     cin>>x;

                     push(x);

              }

              if(str=="pop") pop();

              if(str=="empty"){

                     if(empty()) cout<<"YES"<<endl;

                     else cout<<"NO"<<endl;

              }

              if(str=="query") cout<<query()<<endl;

       }

       return 0;

}

队列

队列是先进先出,头出尾进,要两个变量来记录位置,hh为头,tt为尾

例题:AcWing829

代码:

#include<bits/stdc++.h>

using namespace std;

const int N=1e5+10;

typedef long long ll;

ll qu[N],hh,tt=-1;

void push(int x)//在队尾插入一个x

{

       tt++;

       qu[tt]=x;

}

int pop()//队首弹出一个元素

{

        hh++;

}

int empty()//检查队列是否为空

{

       return hh>tt;

}

int query()//查询队首元素

{

       return qu[hh];

}

int main()

{

       ll m;

       cin>>m;

       while(m--)

       {

              string str;

              cin>>str;

              if(str=="push")

              {

                     int x;

                     cin>>x;

                     push(x);

              }

              if(str=="empty")

              {

                     if(empty()) cout<<"YES"<<endl;

                     else cout<<"NO"<<endl;

              }

              if(str=="query") cout<<query()<<endl;

              if(str=="pop") pop();

       }

       return 0;

}

单调栈

例题:AcWing830

思路:如果用双循环的话必定超时,单调栈和双指针有点类似,可以先模拟一下暴力做法,左边的数比右边的数大的话必定不会作为输出答案,则可以删除

例如,3 2 4的答案是-1 -1 2,这里的3、2都比4小,但是4对应位置输出2,不会是3,就是3在左边比2大则不可能用到就可以删除了。

本题可以用单调栈来存,所谓单调栈就是,栈里面的元素都是单调递增的,先进栈的相当于左边的,要是比后进栈的大的话就能删除,比如上面的3 2 4,3进栈,2进栈,3比2大,退栈,再进4…

代码:

#include<bits/stdc++.h>

using namespace std;

const int N=1e5+10;

typedef long long ll;

ll st[N],n,tt;

int main(){

       scanf("%ld",&n);

       for(int i=0;i<n;i++){

              ll x;

              scanf("%ld",&x);

              while(tt&&st[tt]>=x) tt--;

              if(tt) printf("%ld ",st[tt]);

              else printf("%d ",-1);

              st[++tt]=x;

             

       }

       return 0;

}

单调队列

例题:AcWing154

思路:如果用双循环的话必定超时,单调队列和双指针有点类似,可以先模拟一下暴力做法,左边的数比右边的数大的话必定不会作为输出答案,则可以删除

例如,数列1 3 -1 -3 5,k=3的答案是-1 -3 -3,第一个滑动位置1 3 -1这里的1,3都比-1大,且在-1的前面,就是说有-1的时候不可能会将1、3作为答案输出,则可删除1、3,(可以理解为-1寿命最长且势力大),此时队列第二个滑动窗口3 -1 -3 这里的3、-1都比-3大,同理可删除。

本题可以用单调队列来存,所谓单调队列就是,队列里面的元素队首是最小的,之后依次进队,小的进队首,大的pop掉。

#include<bits/stdc++.h>

using namespace std;

const int N=1e6+10;

typedef long long ll;

ll n,k,a[N],q[N],hh,tt;

int main()

{

       ios::sync_with_stdio(false);

       cin.tie(0);cout.tie(0);

       cin>>n>>k;

       for(int i=0;i<n;i++) cin>>a[i];

       //滑动窗口最小值

       hh=0,tt=-1;

       for(int i=0;i<n;i++)//i为滑到了哪个数

       {

              //判断队头是否已经滑出窗口

              if(hh<=tt&&i-k+1>q[hh]) hh++;//i每加一次必定有一个前面的数要弹出

              //就是先插入的数比先要插入的数大的话

              //则肯定轮不到先插入的数输出,就删除掉它tt--

              while(hh<=tt&&a[q[tt]]>=a[i]) tt--;

              q[++tt]=i;//将这数插入进队列

              if(i>=k-1) cout<<a[q[hh]]<<" ";

       }

       cout<<endl;

      

       //滑动窗口最大值

       hh=0,tt=-1;

       for(int i=0;i<n;i++)//i为滑到了哪个数

       {

              //判断队头是否已经滑出窗口

              if(hh<=tt&&i-k+1>q[hh]) hh++;//i每加一次必定有一个前面的数要弹出

              //就是先插入的数比先要插入的数小的话

              //则肯定轮不到先插入的数输出,就删除掉它tt--

              while(hh<=tt&&a[q[tt]]<=a[i]) tt--;

              q[++tt]=i;//将这数插入进队列

              if(i>=k-1) cout<<a[q[hh]]<<" ";

       }

       cout<<endl;

       return 0;

}

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值