【数据结构】单调队列
文章目录
- 上文链接
- 一、单调队列是什么
- 二、【模板】单调队列 ⭐⭐
- 三、练习 : 质量检测 ⭐⭐
上文链接
单调栈
一、单调队列是什么
什么是单调队列? 单调队列,顾名思义,就是存储的元素始终单调递增或者始终单调递减的队列。注意,这里的队列和普通的 FIFO 队列不一样,它是一个双端队列。
单调队列解决的问题一般用于解决滑动窗口内最大值最小值问题,以及优化动态规划。
二、【模板】单调队列 ⭐⭐
【题目链接】
P1886 滑动窗口 /【模板】单调队列 - 洛谷
【题目描述】
有一个长为 nnn 的序列 aaa,以及一个大小为 kkk 的窗口。现在这个窗口从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最小值和最大值。
例如,对于序列 [1,3,−1,−3,5,3,6,7][1,3,-1,-3,5,3,6,7][1,3,−1,−3,5,3,6,7] 以及 k=3k = 3k=3,有如下过程:
窗口位置最小值最大值[1 3 -1] -3 5 3 6 7 −131 [3 -1 -3] 5 3 6 7 −331 3 [-1 -3 5] 3 6 7 −351 3 -1 [-3 5 3] 6 7 −351 3 -1 -3 [5 3 6] 7 361 3 -1 -3 5 [3 6 7]37\def\arraystretch{1.2} \begin{array}{|c|c|c|}\hline \textsf{窗口位置} & \textsf{最小值} & \textsf{最大值} \\ \hline \verb![1 3 -1] -3 5 3 6 7 ! & -1 & 3 \\ \hline \verb! 1 [3 -1 -3] 5 3 6 7 ! & -3 & 3 \\ \hline \verb! 1 3 [-1 -3 5] 3 6 7 ! & -3 & 5 \\ \hline \verb! 1 3 -1 [-3 5 3] 6 7 ! & -3 & 5 \\ \hline \verb! 1 3 -1 -3 [5 3 6] 7 ! & 3 & 6 \\ \hline \verb! 1 3 -1 -3 5 [3 6 7]! & 3 & 7 \\ \hline \end{array} 窗口位置[1 3 -1] -3 5 3 6 7 1 [3 -1 -3] 5 3 6 7 1 3 [-1 -3 5] 3 6 7 1 3 -1 [-3 5 3] 6 7 1 3 -1 -3 [5 3 6] 7 1 3 -1 -3 5 [3 6 7]最小值−1−3−3−333最大值335567
【输入格式】
输入一共有两行,第一行有两个正整数 n,kn,kn,k;
第二行有 nnn 个整数,表示序列 aaa。
【输出格式】
输出共两行,第一行为每次窗口滑动的最小值;
第二行为每次窗口滑动的最大值。
【示例一】
输入
8 3 1 3 -1 -3 5 3 6 7输出
-1 -3 -3 -3 3 3 3 3 5 5 6 7
【说明/提示】
数据范围
对于 50%50\%50% 的数据,1≤n≤1051 \le n \le 10^51≤n≤105;
对于 100%100\%100% 的数据,1≤k≤n≤1061\le k \le n \le 10^61≤k≤n≤106,ai∈[−231,231)a_i \in [-2^{31},2^{31})ai∈[−231,231)。
【窗口内最大值】
从左往右遍历元素,维护一个单调递减的队列:
当前元素进队之后,注意维护队列内的元素在大小为
k的窗口内;此时队头元素就是最大值。
【窗口内最小值】
从左往右遍历元素,维护一个单调递增的队列:
当前元素进队之后,注意维护队列内的元素在大小为
k的窗口内;此时队头元素就是最小值。
#include<iostream>
#include<deque>using namespace std;const int N = 1e6 + 10;
int a[N];int main()
{int n, k;cin >> n >> k;for(int i = 1; i <= n; i++) cin >> a[i];deque<int> dq;// 求滑动窗口的最小值,构造单调递增的队列for(int i = 1; i <= n; i++){while(dq.size() && a[dq.back()] >= a[i]) dq.pop_back();dq.push_back(i);if(dq.back() - dq.front() + 1 > k) dq.pop_front();if(i >= k) cout << a[dq.front()] << ' ';}cout << endl;dq.clear();// 求滑动窗口的最大值,构造单调递减的队列for(int i = 1; i <= n; i++){while(dq.size() && a[dq.back()] <= a[i]) dq.pop_back();dq.push_back(i);if(dq.back() - dq.front() + 1 > k) dq.pop_front();if(i >= k) cout << a[dq.front()] << ' ';}return 0;
}
三、练习 : 质量检测 ⭐⭐
P2251 质量检测 - 洛谷
套了一个壳子的模板题。
#include<iostream>
#include<deque>using namespace std;const int N = 1e5 + 10;
int a[N];int main()
{int n, m;cin >> n >> m;for(int i = 1; i <= n; i++) cin >> a[i];deque<int> dq;for(int i = 1; i <= n; i++){while(dq.size() && a[dq.back()] >= a[i]) dq.pop_back();dq.push_back(i);if(dq.back() - dq.front() + 1 > m) dq.pop_front();if(i >= m) cout << a[dq.front()] << endl;}return 0;
}
