单调队列入门

单调队列

单调队列是指:
  1. 队列中元素之间的关系具有单调性
  2. 队首和队尾都可以进行出队操作
  3. 只有队尾可以进行入队操作

解题基本思想:

用途:解决区间最值问题

维护队首元素作为答案,去掉多余的元素(维护单调性)。时间复杂度 O(N)


实现方式:
  1. deque 双向队列 (c++容器) 头文件#include < queue > 提供
    deque<int > q;   
    q.push_back();    // 入队
    
    q.pop_back();    // 从队尾出队
    q.pop_front();    // 从队首出队
    
    q.front();      // 获得队首元素 
    

  1. 数组模拟 实现双向队列
int que[100];
int head = 0, tail = 0;
//进队
void push(int a)
{
    que[++tail] = a;
}
//出队
int pop()
{
    return que[++head];
}
//判断队列是否为空
bool empty()
{
    return !(head < tail);
}

  

滑动窗口问题 (洛谷 P1886)

 

输出给定窗口的 最小值 和最大值 序列

思路:
考虑三个地方

  1. 维护入队 ,当元素从队尾 入队, 对前面的 元素的 比较 (维护单调性)与删除(不符合单调性)
    当求最大值序列时,一个元素入队, 需保证 队列中 在它之前的,比它小的 元素都被删除(维护队列 单调递减),
    原因: 当前值 为 较大值 时,显然 之前的较小值 在同一窗口 已无用
    
   
    当求最小值序列时,一个元素入队, 需保证 队列中 在它之前的,比它大的 元素都被删除(维护队列 单调递增)
    原因: 当前值 为 较小值 时,显然 之前的较大值 在同一窗口 已无用
  1. 维护队首 容器队首的元素已经不属于当前窗口的边界,则应该将队首删除
  2. 答案出队,当前位置 满足窗口大小 则记录答案
     
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;

vector<int> mx(int a[],int n,int k)        // 求 滑动窗口 最大值序列
{
    vector<int> ans;
    deque<int >q1;
    
    for(int i=1; i<=n; i++)
    {
        while(!q1.empty()&&a[q1.back()]<a[i])   // 与队尾元素比较,保证 队列 递减,(即删除前面比a[i]小的数)
            q1.pop_back();

        while(!q1.empty()&&i-q1.front()+1>k)    // 与队首 位置比较,判断是否 在当前窗口
            q1.pop_front();

        q1.push_back(i);   // 元素 入队 (下标入队)
      
        if(i>=k)  ans.push_back(a[q1.front()]);      // 记录答案
    }
    return ans;
}

vector<int> mi(int a[],int n,int k)              // 求 滑动窗口 最小值序列
{
    vector<int> ans;
    deque<int >q1;
    
    for(int i=1; i<=n; i++)
    {
        while(!q1.empty()&&a[q1.back()]>a[i])
            q1.pop_back();

        while(!q1.empty()&&i-q1.front()+1>k)
            q1.pop_front();
            
        q1.push_back(i);
        if(i>=k)
            ans.push_back(a[q1.front()]);
    }
    return ans;

}
int a[N];

int main()
{
    ios::sync_with_stdio(false);
    int n,k;


    cin>>n>>k;
    for(int i=1; i<=n; i++)
    {
        cin>>a[i];
    }
    vector<int >c1,c2;
    c1=mi(a,n,k);
    c2=mx(a,n,k);
   
    //输出答案
    for(int i=0;i<c1.size();i++)
    {
        i!=c1.size()-1 ? cout<<c1[i]<<" ":cout<<c1[i]<<endl;
    }
     for(int i=0;i<c2.size();i++)
    {
        i!=c2.size()-1 ? cout<<c2[i]<<" ":cout<<c2[i]<<endl;
    }



    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值