week5 D-滑动窗口 单调队列

题意:

给定一个数组(大小为n),以及一个窗口(大小为k)。窗口在数组上从开始到结尾移动,输出每个位置的窗口里的最大值和最小值。
如图:
在这里插入图片描述

input:

两行数字,第一行两个数字,分别为数组的大小和窗口的大小,其中1<=k<=n<=1000000。

output:

输出有两行。第一行输出滑动窗口在从左到右的每个位置时,滑动窗口中的最小值。第二行是最大值。

思路:

一、可以暴力,依次找出每个串口中的最大值和最小值,但会超时。
二、单调队列,用单调递增队列找出每个窗口的最小值,用单调递减队列找到每个窗口的最大值。以找最小值为例,首先初始化队列,即先将第一个窗口内的值按要求加入队列中去。即当前要加入的数的值如果大于等于队列尾部的值,则直接入队列。否则队尾指针tail–,直到队列为空或者可以大于队尾的值的时候,将其入队列。初始化后,队列第一个数即第一个窗口的最小的值。其后定义窗口左端点和右端点l,r。在每一轮循环中,l++,r++,即窗口移动一个位置。在移动中r对应的数即为要入队列的数,其操作与初始化队列的操作相同。但要判断当前的队首的元素是否在当前的的窗口内,即top如果在当前的队列外,队首出队列,即top++。在窗口每移动一次,便可得到一个当前窗口的最小值。当r到达最右端的n时,循环结束。得到每一个窗口的最小值。最大值得实现与此相同。最后输出即可。

代码:

#include <cstdio>
#include <iostream>
using namespace std;
int a[1000010];

int qu[1000010];
int top=0;
int tail=0;

int main(){
	int n;
	int k;

	scanf("%d %d",&n,&k);
	for(int i=1; i<=n; i++){
		scanf("%d",&a[i]);
	}
	
	tail=1,top=1;
	qu[tail]=1;
	//初始化队列 
	for(int i=2; i<=k; i++){  //找最小的 
		while(tail>0 && a[i]<a[qu[tail]]){
					tail--;
			}
		tail++;
		qu[tail]=i;	
	}
	cout<<a[qu[top]]<<" ";
	int l=1,r=k;
		
	while(r<n){
		if(qu[top]==l) top++;
		r++;
		l++;
		
		while(tail>=top && a[r]<a[qu[tail]]){
				tail--;
		}
		tail++;
		qu[tail]=r;
		
		cout<<a[qu[top]]<<" ";
	}
	cout<<endl;
	

	tail=1,top=1;
	qu[1]=1;
	for(int i=2; i<=k; i++){  //找最大的 
		while(tail>0 && a[i]>a[qu[tail]]){
			tail--;
		}
		tail++;
		qu[tail]=i;			
	}
	
	cout<<a[qu[1]]<<" ";
	l=1,r=k;
	
	while(r<n){
		if(qu[top]==l) top++;
		r++;
		l++;
		
		while(tail>=top && a[r]>a[qu[tail]]){
			tail--;
		}
		tail++;
		qu[tail]=r;
    	cout<<a[qu[top]]<<" ";
	} 
	
	
	return 0;
}
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值