单调队列(Monotonic Queue)是一种特殊类型的队列,通常用于解决一些数组或序列相关的问题。和单调栈类似,单调队列也具有一些特定的性质,在解决一些问题时非常有用。以下是关于单调队列的一些重要点:
-
定义:
- 单调队列是一种数据结构,队列中的元素满足单调递增或单调递减的性质。
-
应用:
- 单调队列通常用于解决一些需要快速找到滑动窗口中的最大值或最小值等问题。它能够在O(1)时间内找到当前队列中的最大值或最小值。
-
实现:
- 在C++中,可以使用双端队列
std::deque
来实现单调队列。通过维护一个递增或递减的双端队列,可以实现单调队列的功能。
- 在C++中,可以使用双端队列
-
算法步骤:
- 在处理数组或序列时,通常需要遍历元素,维护一个单调队列:
- 当新元素加入队列时,从队尾开始,将比当前元素小的元素移除,确保队列保持单调递增或单调递减的性质。
- 当需要获取当前窗口的最大值或最小值时,可以通过队首元素或队尾元素获取。
- 在处理数组或序列时,通常需要遍历元素,维护一个单调队列:
-
时间复杂度:
- 单调队列算法的时间复杂度通常为O(n),其中n是数组或序列的长度。
deque结构的常用操作如下:
#include <iostream>
#include <deque>
int main() {
// 创建一个双端队列
std::deque<int> myDeque;
// 在队尾插入元素
myDeque.push_back(10);
myDeque.push_back(20);
myDeque.push_back(30);
// 在队首插入元素
myDeque.push_front(5);
// 访问队首和队尾元素
std::cout << "Front element: " << myDeque.front() << std::endl; // 输出 5
std::cout << "Back element: " << myDeque.back() << std::endl; // 输出 30
// 弹出队首和队尾元素
myDeque.pop_front();
myDeque.pop_back();
// 获取队列大小
std::cout << "Deque size: " << myDeque.size() << std::endl; // 输出 2
// 遍历队列中的元素
std::cout << "Elements in the deque:";
for (int elem : myDeque) {
std::cout << " " << elem;
}
std::cout << std::endl;
// 清空队列
myDeque.clear();
// 检查队列是否为空
if (myDeque.empty()) {
std::cout << "Deque is empty" << std::endl;
} else {
std::cout << "Deque is not empty" << std::endl;
}
return 0;
}
P1. 洛谷p2032扫描
#include <iostream>
#include <deque>
using namespace std;
// 定义结构体 node,包含值 v 和 id
struct node {
int v;
int id;
};
int main() {
int n, k;
cin >> n >> k;
node* a=new node[n]; // 存放元素的结构体数组
deque<node> qmax; // 保存当前窗口内的最大值
// 输入元素的值和 id
for (int i = 1; i <= n; i++) {
cin >> a[i].v;
a[i].id = i;
}
// 滑动窗口
for (int i = 1; i <= n; i++) {
// 维护 qmax,保存窗口内的最大值
while (!qmax.empty() && qmax.back().v <= a[i].v) {
qmax.pop_back();//单调队列的代码核心
}
qmax.push_back(a[i]);
// 如果窗口大小超过 k,输出当前窗口的最大值
if (i >= k) {
cout << qmax.front().v << endl;
}
// 如果窗口的最大值在窗口外,移除
if (qmax.front().id == i - k + 1) {
qmax.pop_front();
}
}
return 0;
}