滑动窗口 一道单调队列的理解模板题

先来看这个题,理解一下题意,我再来介绍单调队列

F. 滑动窗口

Description
上古文明遗迹中,有一个长度为k的滑动窗口从数组的左端滑到右端,试输出窗口每次移动时窗口里能看到的最大值和最小值。例如有数组为{1,3,-1,-3,5,3,6,7},窗口长度为3,则输出的最大最小值如表
在这里插入图片描述

Input
第一行为两个整数,即n和k(1<n≤1000000)。
第二行为n个整数。

Output
第一行为最小数,第二行为最大数(每行行末均有一空格)。

Samples
Input Copy
8 3
1 3 -1 -3 5 3 6 7
Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7

首先要介绍一下单调队列
我们都知道队列是一种先进先出的数据结构
这就类似于我们在餐厅排队买饭,先排队的人总是先买到饭然后离开这个队列
那么单调队列就是符合队列先进先出特点并且队列元素是单调的数据结构

单调队列可以用数组和指针实现
我们定义一个数组 que[maxn] 来储存队列的下标,定义两个指针 head = 1,tail = 0 来表示头和尾

我们都知道队列有增加、删除这样的操作,对于单调队列来说,如果要增加一个元素,就是把这个元素放到队尾,那么我们直接给指针 tail++ ,然后把新的下标存储下来;如果要删除一个元素,就是让队首元素出队,那么就可以直接让指针 head–,向后指一位即可。

void add(){
	tail++;
}

void erase(){
	head--;
}

单调队列总是满足这样的性质
假设构造递增的单调队列

[i < j]  a[i] < a[j]
[i < j]  a[i] >= a[j]   不存在

所以我们就可以利用这样的性质去构造单调队列
当 head <= tail 并且 a[que[tail]] >= a[i] 的时候,如果把 a[i] 加入队列就不符合单调的性质,但是这个时候显然把单调队列的最后一个元素替换成现在的 a[i] 更优,所以我们更新当前的单调队列。递减的单调队列同理,把 >= 换成 <= 即可。

现在我们就可以做这道题了

int que[maxn], head = 1, tail = 0;
int n,k,a[maxn];

int main(){
	
	io >> n >> k;
	for(int i=1;i<=n;i++) io >> a[i];

	for(int i=1;i<=n;i++){
		while(head <= tail && a[que[tail]] >= a[i]) tail--;
		que[++tail] = i;
		while(i - que[head] + 1 > k) head++;
		if(i >= k) printf("%d ",a[que[head]]);
	}
	puts("");

	head = 1, tail = 0;
	for(int i=1;i<=n;i++){
		while(head <= tail && a[que[tail]] <= a[i]) tail--;
		que[++tail] = i;
		while(i - que[head] + 1 > k) head++;
		if(i >= k) printf("%d ",a[que[head]]);
	}
	puts("");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你数过天上的星星吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值