单调队列

“如果一个选手比你小还比你强,你就可以退役了。”——单调队列的原理

作者写的很好,例子也很形象  :

算法学习笔记(66): 单调队列 - 知乎 (zhihu.com)

可以通过做这道题来理解

 https://leetcode-cn.com/problems/sliding-window-maximum/+一点改进(为什么要加改进是因为就有这么一道题但是那道题找不到了,但是我记得那道题只是在这道题的基础上改了一下输入输出而已)

 改进:1.输入:第一行输入 n (表示有n个数)和  k(表示滑动窗口值,即你只可以看到在滑动窗口内的 k 个数字);第二行输入n个数

            2.输出:第一行输出滑动窗口中最小值,第二行输出滑动窗口最大值

例:输入:8  3

                  1  3  -1  -3  5  3  6  7

       输出:-1 -3  -3  -3  3  3

                  3   3   5   5   6  7

C语言:

这第一个while:while(head<=tail&&q[head]<=i-k) head++; //用来确保队列维护的值是在滑动窗口之内的值
第二个while:while(head<=tail&&a[q[tail]]>a[i]) tail--; //维护单调性
所以通过这两个while就可以保证在一个滑动窗口之内a[q[head]]就是我们要求的最小值。滑动窗口每向右滑动一位,队列就会自行进行维护
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 #include <string.h>
 5 int q[1000001],a[1000001]; //数组q保存的是数组a元素的下标值 !
 6 
 7 int main()
 8 {
 9   int i,n,k;
10   scanf("%d%d",&n,&k);
11   for(i=1;i<=n;i++)
12    scanf("%d",&a[i]);
13   int head=1,tail=0; //为了使队列刚开始为空,下面的head<=tail说明队列不为空
14   for(i=1;i<=n;i++)
15   {
16       while(head<=tail&&q[head]<=i-k) head++;  //超过滑动窗口的大小就弹出前面的元素,这里考虑的是左边下标值,左边下标值在滑动窗口外就是小于滑动窗口最左边下标,所以要head++ 
17       while(head<=tail&&a[q[tail]]>a[i]) tail--;  //单调队列,顾名思义单调递增或者单调递减,如果有破坏其单调性的元素就弹出(这里要理解单调队列的原理 “如果一个选手比你小还比你强,你就可以退役了”) 
18       q[++tail]=i; //入队口
19       if(i>=k)
20        printf("%d ",a[q[head]]);
21   }
22   printf("\n");
23   head=1;tail=0;
24   for(i=1;i<=n;i++)
25   {
26       while(head<=tail&&q[head]<=i-k) head++;
27       while(head<=tail&&a[q[tail]]<a[i]) tail--;
28       q[++tail]=i;
29       if(i>=k)
30        printf("%d ",a[q[head]]);
31   } //这里是求最大值,与前面求最小值一样,只是单调队列维护的单调性不同而已 
32   return 0;
33 }
34 
35  

 可对照 “31天刷题打卡”分类栏里第27天的第一题  一起看,那个是C++版本的

posted @ 2022-07-23 10:27  balabalahhh  阅读(73)  评论(0)    收藏  举报