【模板】滑动窗口最值(单调队列)/洛谷P1886

1|0题目链接

https://www.luogu.com.cn/problem/P1886

2|0题目大意

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

3|0题目解析

使用 C++STL 库中的 deque
以窗口最小值为例,设该双端队列为 Q ,其队头则为每一次的答案:
首先,保证 Q 中均为未过期的值(即, Q 中元素均在窗口中)。
然后,比较 Q 的队头与新加入的值 a[i]

  • a[i] 更小,则可以清空队列,加入 a[i] (因为此时 a[i] 不但最新,而且最小)。
  • 若原队头更小,将 a[i] 加入队尾,但是在加入之前,确保 a[i] 大于队尾(如果 a[i] 队尾,则明显更优,队尾就废弃直接弹出了)。

这样,就可以保证答案的正确性了。
其次,我们来考虑复杂度,队列中长度总不大于窗口大小,每一个元素只进出一次, a[i] 总比较次数不超过 n 次,因此总的时间复杂度为 O(n)
最大值同理。

4|0参考代码

#include <bits/stdc++.h> using namespace std; deque <pair <int, int> > Q; vector <int> a; int main() { int n, k, x; scanf("%d%d", &n, &k); for (int i = 0; i < n; ++i) { scanf("%d", &x); a.push_back(x); } /*求滑动窗口最小值*/ for (int i = 0; i < n; ++i) { if (!Q.empty()) { if (a[i] <= Q.front().first) {Q.clear(); Q.emplace_front(a[i], i);} else { while (a[i] <= Q.back().first) Q.pop_back(); Q.emplace_back(a[i], i); } } else Q.emplace_back(a[i], i); if (i >= k-1) { while (!Q.empty() && Q.front().second < i-k+1) Q.pop_front(); if (!Q.empty()) printf("%d ", Q.front().first); } } putchar('\n'); Q.clear(); /*求滑动窗口最大值*/ for (int i = 0; i < n; ++i) { if (!Q.empty()) { if (a[i] >= Q.front().first) {Q.clear(); Q.emplace_front(a[i], i);} else { while (a[i] >= Q.back().first) Q.pop_back(); Q.emplace_back(a[i], i); } } else Q.emplace_back(a[i], i); if (i >= k-1) { while (!Q.empty() && Q.front().second < i-k+1) Q.pop_front(); if (!Q.empty()) printf("%d ", Q.front().first); } } putchar('\n'); return 0; }

感谢支持!


__EOF__

本文作者炯炯目光
本文链接https://www.cnblogs.com/jjmg/p/13604408.html
关于博主:KTH 信息与网络工程硕士在读
版权声明:欢迎分享或转载
声援博主:To be or not to be, is a question.
posted @   Chiron-zy  阅读(205)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示