week5作业——D:滑动窗口

主要思路:

与A题最大矩形类似,本题我们需要维护一个单调队列(单调队列描述的是局部的单调性,恰恰对应了本题)
(以求解最小值为例,求最大值类似)我们维护一个单调队列(由首至尾递增),当队列为空或者队尾元素小于待入元素,那么可以入队;否则一直弹出直至符合上述情况。除了完成上述步骤,由于题目有个长度为k的区间的限制,我们还需要检查是否满足这一条件,即当前区间长度若超过k则需要弹出一个(而且这里明确要弹掉队首元素,因为我们的区间是从左向右移动),最后更新答案即可

奇怪的坑

代码在G++就TLE,在C++就能过;也没有用任何的stl,目前还没有找到原因

D - 滑动窗口

ZJM 有一个长度为 n 的数列和一个大小为 k 的窗口, 窗口可以在数列上来回移动. 
现在 ZJM 想知道在窗口从左往右滑的时候,每次窗口内数的最大值和最小值分别是多少. 
例如:数列是 [1 3 -1 -3 5 3 6 7], 其中 k 等于 3. 
Window position 		Minimum value 			Maximum value
[1  3  -1] -3  5  3  6  7  	-1						3
 1 [3  -1  -3] 5  3  6  7  	-3						3
 1  3 [-1  -3  5] 3  6  7  	-3						5
 1  3  -1 [-3  5  3] 6  7  	-3						5
 1  3  -1  -3 [5  3  6] 7  	3						6
 1  3  -1  -3  5 [3  6  7] 	3						7

Input

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

Output

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

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

A Possible Solution

#include<stdio.h>

const int maxn=1e6+50;
int n,k,arr[maxn],
	max[maxn],min[maxn],dq[maxn];
 
int main(){
	scanf("%d %d",&n,&k);
	for(int i=0;i<n;i++)
		scanf("%d",arr+i);
	
	int top=0,btm=1;
	for(int i=0;i<n;i++){
		
		while( top>=btm && arr[dq[top]]>=arr[i] ){
			top--;
		}
		
		top++;
		dq[top]=i;
		
		if(dq[top]-dq[btm]+1>k){
			btm++;
		}
		
		min[i]=arr[dq[btm]];
		
	}
	
	top=0;btm=1;
	for(int i=0;i<n;i++){
		
		while( top>=btm && arr[dq[top]]<=arr[i] ){
			top--;
		}
		
		top++;
		dq[top]=i;
		
		if(dq[top]-dq[btm]+1>k){
			btm++;
		}
		
		max[i]=arr[dq[btm]];
		
	} 
	
	for(int i=k-1;i<n-1;i++)
		printf("%d ",min[i]);
	printf("%d\n",min[n-1]);
	
	for(int i=k-1;i<n-1;i++)
		printf("%d ",max[i]);
	printf("%d\n",max[n-1]);
	return 0;
}
发布了26 篇原创文章 · 获赞 0 · 访问量 488

猜你喜欢

转载自blog.csdn.net/weixin_43669888/article/details/105132936