【程序设计思维与实践 Week5 作业D】滑动窗口

题目描述:

有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 现在 我们想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少.
例如:数列是[1 3 -1 -3 5 3 6 7], 其中 k 等于 3。
在这里插入图片描述

输入说明:

输入有两行。第一行两个整数n和k分别表示数列的长度和滑动窗口的大小,1<=k<=n<=1000000。第二行有n个整数表示数列。

Sample Input:
8 3
1 3 -1 -3 5 3 6 7

输出说明:

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

Sample Output:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

思路:

这是是要求取大小为K的滑动窗口内的最值,是一个局部的概念,我们仍然可采用与作业A当中单调栈类似的思想,单调栈可求取全局范围内的最值,因为这里是一个局部的概念,因此,对于不属于当前范围的元素应去除,故队首元素会因窗口向右滑动而可能被去除,这是一个单调队列的思想。
建立一个单调递增的队列,依次压入各个数字,若要压入的数不满足队列的单调性,则将队尾元素移除,直到要压入的元素满足单调性,压入之后,应对队首元素进行考察,是否属于当前范围(因为每次只压入一个元素所以只考虑队首一位即可),若不属于当前范围,则将其移除,此时队首元素即为以压入元素为右边界的滑动窗口内的最小元素,直到压入最后一个数,此时便求出了所有窗口的最小值。
同理建立一个单调递减队列,即可求出每个窗口位置的最大值。

代码:

#include <iostream>
using namespace std;
const int size=1e6+10;
int st[size],val[size];
int Min[size],Max[size];
int l=1,r=0,n,k;
int main(int argc, char** argv) {
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",val+i);
	for(int i=1;i<=n;i++)
	{
		while(l<=r&&val[st[r]]>val[i]) r--;
		st[++r]=i;
		if(l<=r&&st[r]-st[l]+1>k) l++;
		Min[i]=val[st[l]];
	} 
	l=1;r=0;
	for(int i=1;i<=n;i++)
	{
		while(l<=r&&val[st[r]]<val[i]) r--;
		st[++r]=i;
		if(l<=r&&st[r]-st[l]+1>k) l++;
		Max[i]=val[st[l]];
	} 
	for(int i=k;i<=n;i++)
		printf("%d ",Min[i]);
	printf("\n");
	for(int i=k;i<=n;i++)
		printf("%d ",Max[i]);
	printf("\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值