当前位置:   article > 正文

洛谷:P2032 扫描(彻底搞懂单调队列)_洛谷b2032

洛谷b2032

传送门:P2032 扫描 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2032

题目描述

4644aeed2c1a4bad8a3069b1fd852555.png

用暴力解法时间复杂度为O(k*n)显然是不能通过有的示例的,我们可以考虑优化,有什么算法可以直接得到k区间的最大值呢?

这个时候就引入了单调队列,我们知道单调队列可以维护一个区间的最大值和最小值,既然是单调队列,那我们是要用单调递增的队列,还是用单调递减的队列呢?

下面可以找到答案。

求解步骤和思路可以参考求m区间内的最小值滑动窗口

洛谷:P1440 求m区间内的最小值_´悠 子ᴗ`-_-╭☞ꪗꪖꪑ的博客-CSDN博客用单调队列来求解求m区间内的最小值https://blog.csdn.net/qq_66500237/article/details/127797778?utm_source=app&app_version=5.5.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

或:

洛谷:P1886 滑动窗口 /【模板】单调队列题解_´悠 子ᴗ`-_-╭☞ꪗꪖꪑ的博客-CSDN博客用单调队列求解移动窗口https://blog.csdn.net/qq_66500237/article/details/127803829

对于这题的本质就是滑动窗口求每个k区间的最大值,我们用一个单调队列去维护队首为最大值,也就是说这个单调队列为一个相对于队首来说的单调递减的队列,队首就是最大。要注意的是,每次入队都要保证队首在k区间内,还要保证队列的单调性。

单调递减队列有:(我这里的递减是相对于队首的递减)

  1. for(int i=1;i<=n;i++){
  2. while(q[front]<=i-k&&front<=rear)front++;//保证队首在k区间内
  3. while(front<=rear&&a[q[rear]]<=a[i])rear--;//保证队列的单调性
  4. q[++rear]=i; //入队
  5. }

front 和 rear 分别为头指针和尾指针。

如 案例中的 n=5,k=3 {1,5,3,4,2}

队列中情况队列操作
1队列为空,1入队
55>1,1出队,5入队
5 33<5,3入队
5 44>3,3出队,4<5,4入队
4 25超出了k区间,5出队,2<4,2入队

 从队列的整个操作过程我们可以知道,队首就是我们要找的最大值,而且也维护了队首在k区间内,这就是单调队列求k区间的最大值的好处。

代码:

  1. #include<iostream>
  2. using namespace std;
  3. int q[2000005],a[2000005],n,k,front=1,rear=0;
  4. int main(){
  5. cin>>n>>k;
  6. for(int i=1;i<=n;i++){
  7. cin>>a[i];
  8. while(q[front]<=i-k&&front<=rear)front++;//保证队首在k区间内
  9. while(front<=rear&&a[q[rear]]<=a[i])rear--;//保证队列的单调性
  10. q[++rear]=i; //入队
  11. if(i>=k)cout<<a[q[front]]<<"\n";
  12. }
  13. return 0;
  14. }

6f294312490e4db088929eff797825c6.png

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号