【CODEVS4373】窗口(单调队列)

题目链接

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;
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/81462502