P1886 滑动窗口(单调队列)

这篇博客介绍了如何利用双端队列(deque)有效地计算一个给定序列中滑动窗口的最大值和最小值。通过维护两个有序的deque,分别用于跟踪最大值和最小值,每次窗口滑动时更新队列,从而在O(1)的时间复杂度内获取当前窗口的最大值和最小值。这种方法适用于处理大规模数据,例如序列长度n可达10^6,窗口大小k不超过n的情况。
摘要由CSDN通过智能技术生成

滑动窗口

传送门

题目描述

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

例如:

The array is [1,3,-1,-3,5,3,6,7], and k = 3。

在这里插入图片描述

输入格式

输入一共有两行,第一行有两个正整数 n,k。 第二行 n 个整数,表示序列 a。

输出格式

输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值

输入样例

8 3
1 3 -1 -3 5 3 6 7

输出样例

-1 -3 -3 -3 3 3
3 3 5 5 6 7

【数据范围】

对于 50% 的数据, 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105
对于 100% 的数据, 1 ≤ k ≤ n ≤ 1 0 6 1\le k \le n \le 10^6 1kn106 a i ∈ [ − 2 31 , 2 31 ) a_i \in [-2^{31},2^{31}) ai[231,231)

思路

用deque来维护一个递增的序列和一个递减的序列,每次入队时清理队头、队尾的无效元素。剩下的队头元素就是最大值、最小值了。

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
struct N{int v,p;};
deque<N> big,sma;
int n,k,v,ansb[maxn],anss[maxn];

int main(){
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&v);
        while(big.size()&&big.back().v>=v)   big.pop_back();
        while(big.size()&&i-big.front().p>=k) big.pop_front();
        big.push_back({v,i});
        while(sma.size()&&sma.back().v<=v)   sma.pop_back();
        while(sma.size()&&i-sma.front().p>=k) sma.pop_front();
        sma.push_back({v,i});
        ansb[i]=sma.front().v;
        anss[i]=big.front().v;
    }
    for(int i=k-1;i<n;i++)  printf("%d%c",anss[i],i==n-1?'\n':' ');
    for(int i=k-1;i<n;i++)  printf("%d%c",ansb[i],i==n-1?'\n':' ');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值