欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D - 滑动窗口(Week5作业)

程序员文章站 2022-05-04 17:13:24
...

题目

给定一个大小为n≤106n≤106的数组。
有一个大小为k的滑动窗口,它从数组的最左边移动到最右边。
您只能在窗口中看到k个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为[1 3 -1 -3 5 3 6 7],k为3。
D - 滑动窗口(Week5作业)
您的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

输入格式

输入包含两行。
第一行包含两个整数n和k,分别代表数组长度和滑动窗口的长度。
第二行有n个整数,代表数组的具体数值。
同行数据之间用空格隔开。

输出格式

输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。

输入样例:

8 3
1 3 -1 -3 5 3 6 7

输出样例

-1 -3 -3 -3 3 3
3 3 5 5 6 7

题目思路:

1、典型的单调队列题目
	·指针 trail 指向队尾,判断新进入窗口的数是否比队尾中的大/小,符合条件入栈(找最大值时,比队尾小入队列,否则,队尾出队列,数据再入队列)
	·指针 head 指向队首,判断当前队首是否在滑动窗口中,若不在head++
2、可以利用数组模拟队列过程,速度更快,处理更方便;
3、可以选择用一个队列记录每次入队列的数组索引,方便 head 指针判断是否弹出队首。

(ps:以后交代码,出现tle记得换个编译器试试,一直tle最后换了个编译器通过了,顺便把之前tle版本也都测试了一下,也ac了。。。惨痛教训)

代码实现:

第一种:

#include<cstdio>
#include<cstring>
using namespace std;
int term[1000005];
int a[1000005];
int n,k;
void windoww(int z)
{
 int head=0;
 int trail=-1;
 for(int i=0;i<n;i++)
 {
  while((z*term[i])>=(z*term[a[trail]]) && trail>=head) trail--;
  a[++trail]=i;
  while(a[head]<=i-k && trail>=head) head++;
  if(i>=k-1) printf("%d ",term[a[head]]);
 }
 printf("\n");
}
int main()
{
 scanf("%d %d",&n,&k);
 for(int j=0;j<n;j++)
  scanf("%d",&term[j]);
 windoww(-1);
 windoww(1);
 return 0;
}

对于实现代码的中间/其他思路:

void windoww(int z,int n,int k)
{
	start=0;
	end=k;
	head=0;
	trail=-1;
	for(int i=0;i<n;i++)
		q[i]=0;
	for(int i=0;i<n;)
	{
		while(i>=start&&i<end)
		{
			if(trail<head)
			{
				trail++;
				q[trail]=term[i];
				i++;
				continue;
			}
			while(z*term[i]>z*q[trail]&&trail>head-1) trail--;
			trail++;
			q[trail]=term[i];
			i++;
		}
		printf("%d ",q[head]);
		start++;
		end++;
		if(q[head]==term[start-1]) head++;
	}
	printf("\n");
}
void windoww(int z)
{
	int head=0;
	int trail=-1;
	for(int i=0;i<n;i++)
	{
		while((z*term[i])>=(z*term[a[trail]]) && trail>=head) trail--;
		a[++trail]=i;
		while(a[head]<=i-k && trail>=head) head++;
		if(i>=k-1) printf("%d ",term[a[head]]);
	}
	printf("\n");
}
相关标签: C++