主要思路:
与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;
}