单调队列的介绍及相关例题

一.单调队列.

一.单调队列的介绍

单调队列 是 队列中元素之间的关系具有单调性,队列中的元素始终保持着单增或者单减的特性,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作,本质是有双端队列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~

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python的单调队列是一种用于解决某些特定问题的数据结构。它是队列的一种变体,可以快速查询当前队列中的最大或最小元素。 单调队列通常用于需要维护当前滑动窗口中的最大或最小值的情况。例如,假设我们有一个长度为n的数组arr和一个窗口大小为k的滑动窗口。我们想要找到每个窗口中的最大值。单调队列就可以帮助我们在O(n)的时间复杂度内实现。 实现单调队列需要两个操作:push(x)和pop()。push(x)用于向队列的尾部添加元素x,而pop()用于从队列的头部删除元素。这两个操作具有O(1)的时间复杂度。 当我们向队列中添加一个新元素时,为了维护队列单调性,我们需要从队列的尾部删除一些元素。具体来说,我们从队列的尾部开始,不断地删除比新元素小的元素,直到队列为空或者新元素大于等于队列尾部元素为止。这样,我们就可以保证队列中的元素是以递减顺序排列的。 当我们需要查询当前队列中的最大或最小值时,只需访问队列头部的元素即可。由于队列中的元素是以递减的顺序排列的,所以头部元素就是最大值(或最小值)。 总的来说,Python的单调队列是一种高效的数据结构,可以用于解决一些特定问题,如滑动窗口中的最大(或最小)值。它具有O(n)的时间复杂度,并且可以通过push(x)和pop()操作来维护队列单调性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值