单调队列
单调队列就是维持出队顺序是单调的。
下面分析一下用数组存储是怎样维护单调队列的:
用数组存储和记录的话,可以从两个方向出去,只需要记录l,r这两个指针即可。
具体题目:
ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少. 例如:
数列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3.
题目分析
这个题目只需要维护局部的单调性即可,那么就是用单调队列。如果要求局部最小值,那么就是维护单调单调增队列,最开始的那一个就是最小值。
当加入的元素小于最末尾的元素,那么就r–(覆盖掉应该出队列的元素);而且要注意的是当l,r指针所指的下标距离如果大于k,那么就表示到达了另外一个局部,就要l++。
全部代码:
#include<stdio.h>
int n,k;
int a[1000002],q[1000002];
void tmin()
{
int l = 1, r = 0; // l < r
for(int i = 1; i <= n; i++){
while(r >= l && a[q[r]] >= a[i]) r--; // 寮瑰嚭闃熷熬
q[++r] = i; // 涓嬫爣
if(q[r]-q[l]+1 > k) l++;
if(i>=k) printf("%d ",a[q[l]]);
}
printf("\n");
}
void tmax()
{
int l = 1, r = 0; // l < r
for(int i = 1; i <= n; i++){
while(r >= l && a[q[r]] <= a[i]) r--; // 寮瑰嚭闃熷熬
q[++r] = i; // 涓嬫爣
if(q[r]-q[l]+1 > k) l++;
if(i>=k) printf("%d ",a[q[l]]);
}
printf("\n");
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
//单调队列
tmin();
tmax();
return 0;
}