牛客每日一题 3月20日 滑动窗口(优先队列)

滑动窗口(优先队列)

题目链接:滑动窗口

牛客每日一题 3月20日 滑动窗口(优先队列)_第1张图片

题解:

我们用一个双端队列来维护(普通的队列只能从队尾加入元素从队首删除元素,双端队列的队尾也可也删除元素),区间每次右移一个单位,首先看看队首的元素是否超出了范围,如果超出了,就把它删掉;然后将新进入区间的这个元素往双端队列里放,但放进来之前需要判断队尾(也就是还有可能成为最大值的最后一个元素)是不是小于最后一个元素,如果是,就把这个队尾删掉,一直到前一个元素大于等于它为止。由于我们队列里面的元素实际上是单调不增的,每次的最大实际上就在队首。而由于每个数进队和出队的次数都只有一次,时间复杂度是{O(n)}O(n)的。

代码

#include 
#include 
using namespace std;
const int MAXN = 1e6+5;

int a[MAXN];
int que[MAXN];

int main() {
    int N, K;
    scanf("%d%d", &N, &K);
    for(int i = 1; i <= N; i++) {
        scanf("%d", &a[i]);
    }



    //递减单调队列
    int l = 0;
    int r = 1;
    que[0] = 1;
    if(K == 1)
        printf("%d ", a[1]);
    for(int i = 2; i <= N; i++) {
        if(i - que[l] >= K && (l < r))
            l++;
        while((r > l) && a[que[r - 1]] >= a[i]) {
            r--;
        }
        que[r++] = i;
        if(i >= K)
            printf("%d ", a[que[l]]);
    }
    printf("\n");


    //递增单调队列
    l = 0;
    r = 1;
    que[0] = 1;
    if(K == 1)
        printf("%d ", a[1]);
    for(int i = 2; i <= N; i++) {
        if(i - que[l] >= K && (l < r))
            l++;
        while((r > l) && a[que[r - 1]] <= a[i]) {
            r--;
        }
        que[r++] = i;
        if(i >= K)
            printf("%d ", a[que[l]]);
    }
    printf("\n");
    return 0;
}

你可能感兴趣的:(牛客,题解,队列,算法)