单调队列C++

单调队列

一、概念

单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

单调队列顾名思义就是一个有规律的队列,这个队列的规律是:所有在队列里的数都必须按递增(或递减)的顺序列队。

例如:

有如下一串数字:1 5 3 4 2
首先第一个数字1先进队列,que = {1};
之后第二个数字5大于1,则1出队列5进队列,que = {5};
下一步第三个数字3小于5,进队列,que = {5,3};
下一步第四个数字4大于3,则3出队列4进队列,que = {5,4};
下一步第五个数字2小于4,进队列,que = {5,4,2};
这样最后队列里的数字为单调递减排列。

二、模板:

//que数组存储数据在a数组中的下标
que[++tail] = 1;//第一个数据先进入队列
for(int i = 2; i <= n; i++){
       while(head<= tail && i - que[head] == k)//判断最大的数是否在范围之内,若不在则出队列
              head++;
       while(head<= tail && a[i] >= a[que[tail]])//当新插入的数比队尾大时,弹出队尾的数
              tail--;
       que[++tail]= i; //新插入的数进入队列
       if(i>= k)
              printf("%d\n",a[que[head]]);
       }

三、例题:

题目描述

有一个 1 x n 的矩阵,有n个整数。
现在给你一个可以盖住连续k个数的木板。
一开始木板盖住了矩阵的第i~k 个数,每次将木板向右移动一个单位,直到右端与第n个数重合。
每次移动前输出被覆盖住的数字中最大的数是多少。

输入格式

第一行两个整数n,k,表示共有 n 个数,木板可以盖住 k 个数。
第二行n个整数,表示矩阵中的元素。

输出格式

共 n - k + 1行,每行一个整数。
第i行表示第 i ~i + k - 1个数中最大值是多少。

样例输入

5 3
1 5 3 4 2

样例输出

5     5     4

AC代码;

#include<stdio.h>
#define maxn 2000001
int head = 1, tail = 0;
int a[maxn], que[maxn];
 
int main(){
       int n,k;
       scanf("%d%d", &n, &k);
       for(inti = 1; i <= n; i++){
              scanf("%d",&a[i]);
       }
       //单调队列递减,则队头为最大元素
       que[++tail]= 1;
       for(inti = 2; i <= n; i++){
              while(head<= tail && i - que[head] == k)//判断最大的数是否在范围之内,若不在则出队列
                     head++;
              while(head<= tail && a[i] >= a[que[tail]])//当新插入的数比队尾大时,弹出队尾的数
                     tail--;
              que[++tail]= i; //新插入的数进入队列
              if(i>= k)
                  printf("%d\n", a[que[head]]);
       }
       return0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单调队列(Monotonic Queue)是一种数据结构,它可以用来解决一类滑动窗口问题。滑动窗口问题是指在一个长度为n的数组中,长度为k的窗口从左往右移动,每次移动一位,求出每个窗口的最大值或最小值。 单调队列的思想就是维护一个单调递增或递减的队列,队列中的元素从队头到队尾是单调递增或递减的。当窗口向右移动时,先将队头元素出队,然后将新的元素从队尾入队,保持队列的单调性。这样就可以实现每个窗口的最大值或最小值的求解。 下面是单调队列求解滑动窗口最大值的C++代码: ```c++ vector<int> maxSlidingWindow(vector<int>& nums, int k) { vector<int> res; deque<int> dq; for (int i = 0; i < nums.size(); i++) { // 如果队列中的元素个数超过了窗口大小,就将队头元素出队 if (!dq.empty() && dq.front() == i - k) { dq.pop_front(); } // 将队列中比要加入的元素小的元素全部出队 while (!dq.empty() && nums[dq.back()] < nums[i]) { dq.pop_back(); } // 将新元素加入队列 dq.push_back(i); // 取当前窗口的最大值 if (i >= k - 1) { res.push_back(nums[dq.front()]); } } return res; } ``` 在上述代码中,使用双端队列deque来实现单调队列。dq.front()表示队头元素的下标,dq.back()表示队尾元素的下标。当队列为空时,dq.front()和dq.back()都是未定义的。 时间复杂度:O(n),每个元素最多被插入和删除一次。 空间复杂度:O(k),队列中最多存储k个元素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值