Update queue
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Sainnhe Park 2022-12-15 17:11:43 +08:00
parent 2f063c519e
commit f46902b970

View File

@ -18,7 +18,7 @@
使用场景:
1. 先进先出的数据结构
2. 滑动窗口
2. 滑动窗口最值问题
### 变体:优先级队列
@ -65,6 +65,64 @@ Not empty
经典题目:[239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/)
奇技淫巧:随机删除元素
现在我们想以 `O(logn)` 的时间复杂度来删除元素,应该怎么做呢?
思路很简单,维护另一个优先队列——删除队列。
当我们要删除一个元素时,我们并不真的在原队列中删除它,而是把它放到删除队列中;
当我们要访问原队列栈顶时,看看原队列栈顶是不是等于删除队列栈顶,如果是,则循环删除原队列和删除队列的栈顶,直到栈顶不想等或者为空。
为什么这样做一定是正确的呢?有没有可能我们想要删除 x ,原队列栈顶也是 x ,而删除队列栈顶是 y ( y >= x ) 呢?
这是不可能的,因为如果 y >= x ,那么原队列栈顶就不可能是 x 。
### 变体:单调队列
优先队列有另外一个名字:二叉堆,它的数据结构本质上并不是队列,时间复杂度不是线性的。
是否有线性复杂度的数据结构呢?
有,这就是单调队列。
单调队列的特性如下:
1. 它的数据结构本质依然是队列,因此具有线性时间复杂度
2. 它并不能保证你弹出一个元素后,这个元素就真的在队列里删除了,也有可能当你在插入元素时会删掉队列里的其它元素
3. 它能保证的是,队列中所有元素单调(递减),队首元素一定是队列里的最值。
经典题目:[239. 滑动窗口最大值](https://leetcode.cn/problems/sliding-window-maximum/)
我们看看这道题里的单调队列是怎么实现的。这里我们采用 `deque` ,相比于 `queue` ,它能同时对队首和队尾进行操作。
```cpp
#include <deque>
class MyQueue {
public:
std::deque<int> que;
void pop(int value) {
// 只有当要弹出的元素等于队首时,才会弹出
// 这样做没问题吗?
// 没问题,因为我们只关注队首元素是不是最大的,只要我们想弹出的元素不是队首元素,那就可以不用管
if (value == que.front() && !que.empty()) {
que.pop_front();
}
}
void push(int value) {
// 当我们要插入的元素比队尾元素大时,就一直弹出队尾元素,直到小于等于队尾元素为止?
// 这样做没问题吗?
// 没问题,因为我们只关注队首元素是不是最大的,其它元素要不要都无所谓。
while (value > que.back() && !que.empty()) {
que.pop_back();
}
que.push_back(value);
}
int front(void) { return que.front(); }
};
```