B

题意

  给你一串长为n的序列,给你一个整数k代表窗口的长度为k,从序列左端到右端,你需要找到每个连续的长度为k的区间的最小值和最大值

思路

  如果暴力来做,遍历n次k个数,那就是n方的复杂度;如果维护一个线段树那就是nlogn,每个数只被插入一次和删除一次。

  我们可以维护两个单调队列,单调递增队列用于计算窗口的最小值,每删去一个数就看队头有没有出去,出去就出队,新增一个数就和队尾比较,直到能放下去,维护n次,每次的队头就是区间的最小值,最大值同理,复杂度为n。

AC代码

#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=1e6+5;
int a[maxn],que[maxn],label[maxn];
int n,k,head,tail;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    head=1;tail=0;
    for(int i=1;i<=n;i++){
        while(head<=tail&&i-label[head]>=k) head++;
        while(head<=tail&&que[tail]>=a[i]) tail--;
        que[++tail]=a[i];
        label[tail]=i;
        if(i>=k)
        printf("%d ",que[head]);
    }
    printf("
");
    head=1;tail=0;
    for(int i=1;i<=n;i++){
        while(head<=tail&&i-label[head]>=k) head++;
        while(head<=tail&&que[tail]<=a[i]) tail--;
        que[++tail]=a[i];
        label[tail]=i;
        if(i>=k)
        printf("%d ",que[head]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/qq2210446939/p/12722726.html