4373 窗口
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 黄金 Gold
题解
题目描述 Description
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
Window position | Min value | Max 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 |
你的任务是找出窗口在各位置时的max value, min value.
输入描述 Input Description
第1行n,k,第2行为长度为n的数组
扫描二维码关注公众号,回复:
2635440 查看本文章
输出描述 Output Description
2行
第1行每个位置的min value
第2行每个位置的max value
样例输入 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
数据范围及提示 Data Size & Hint
数据范围:20%: n<=500; 50%: n<=100000;100%: n<=1000000;
解题思路:
利用单调队列来维护区间的最小值和最大值,Q1维护的是最小值的单调队列,Q2维护的是最大值的单调队列,这里需要先让k个元素先进队列,然后输出n-k个最小值与最大值。
代码:
#include<cstdio>
using namespace std;
int a[1000005],Q1[1000005],Q2[1000005],Min[1000005],Max[1000005];
int main()
{
int n,k,n1=0,n2=0;
scanf("%d%d",&n,&k);
int rear1=0,head1=1,rear2=0,head2=1;
for(int i=1;i<=k;i++)
{
scanf("%d",&a[i]);
while(rear1>=head1 && a[Q1[rear1]]>=a[i])rear1--;
Q1[++rear1]=i;
while(rear2>=head2 && a[Q2[rear2]]<=a[i])rear2--;
Q2[++rear2]=i;
}
for(int i=k+1;i<=n;i++)
{
Min[n1++]=a[Q1[head1]];
Max[n2++]=a[Q2[head2]];
scanf("%d",&a[i]);
while(rear1>=head1 && a[Q1[rear1]]>=a[i])rear1--;
Q1[++rear1]=i;
while(i-k+1>Q1[head1])head1++;
while(rear2>=head2 && a[Q2[rear2]]<=a[i])rear2--;
Q2[++rear2]=i;
while(i-k>=Q2[head2])head2++;
}
Min[n1++]=a[Q1[head1]];
Max[n2++]=a[Q2[head2]];
printf("%d",Min[0]);
for(int i=1;i<n1;i++)printf(" %d",Min[i]);
printf("\n");
printf("%d",Max[0]);
for(int i=1;i<n2;i++)printf(" %d",Max[i]);
printf("\n");
return 0;
}