单调队列
“如果一个选手比你小还比你强,你就可以退役了。”——单调队列的原理
作者写的很好,例子也很形象 :
算法学习笔记(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++版本的

浙公网安备 33010602011771号