基础知识
GeeksforGeeks: Priority Queue of Pairs - 了解更多自定义优先队列的用法。
优先队列(Priority Queue) 也称堆,是一种数据结构,可以快速获取优先级最高的元素(如最大、最小或自定义的优先级)。
- 大顶堆: 值越大的元素优先级越高,越在上面。
- 小顶堆: 值越小的元素优先级越高,越在上面。
一般操作时间复杂度:
- 插入 (Insertion): O(log N)
- 删除 (Deletion): O(log N)
- 访问堆顶元素: O(1)
与 set 等其他容器不同的是,优先队列内部无序,只满足堆的性质,能够快速获得极值。
基本操作
以下是 C++ 中 priority_queue 的基本用法:
que.size(); // 获取元素数量
que.push(10); // 插入元素
que.top(); // 返回优先级最高的元素
que.pop(); // 删除优先级最高的元素
que.empty(); // 判断队列是否为空
priority_queue<int> que1; // 默认大顶堆,最大元素最先pop
priority_queue<int, vector<int>, greater<int>> que2; // 小顶堆,最小元素最先pop
struct Node {
int x, y;
bool operator < (const Node& b) const {
return this->x < b->x; // x越大排在越前面,大顶堆中最大优先pop
}
};
int main() {
priority_queue<Node> que;
que.push({1, 5});
que.push({3, 2});
que.push({2, 8});
while (!que.empty()) {
cout << que.top().x << " ";
que.pop();
}
// 输出:3 2 1
}
Leetcode相关题目
priority_queue<int> 的常见应用有两个,一个是 Top K 问题,另一个是 找中位数 问题。
简单难度 (Easy)
中等难度 (Medium)
- 347. 前 K 个高频元素
👉 这道题用vector sort方法做会更快。
困难难度 (Hard)
-
239. Sliding Window Maximum
👉 这道题用priority_queue实在是太巧妙了。 -
480. Sliding Window Median
👉 Meta 30天挑战中遇到的题。 -
295. Find Median from Data Stream
👉 通过维护两个堆来实现,分别是大顶堆和小顶堆。第一次只维护了一个大顶堆,结果丢失了关键信息。后来发现,维护两个堆(大顶堆 + 小顶堆)可以确保更好地获取中位数。单独维护一个堆会导致信息丢失,无法完整获取数据分布。 -
407. Trapping Rain Water II 👉 通过最小堆从边界向内扩散,每次以当前最低边界决定水位高度,并更新周围未访问的邻居:
若邻居高度低于当前边界,则视为能接水。最小堆推进(高度更新为当前边界高度);否则保留原高度。
这一过程模拟“水往低处流”的灌水逻辑,同时有效防止遗漏中间洼地。
代码细节和注意事项
-
Priority Queue 允许重复值
示例代码:priority_queue<int> que; vector<int> v = {1, 2, 2, 4, 5, 6, 8, 8}; for (auto& num : v) { que.push(num); if (que.size() > 3) que.pop(); // 保留前3个最大的元素 } cout << que.top(); // 输出3个最大数中的最小值 -
做题时注意细节
如果要求第k大元素,则要使用小顶堆,这样可以保证堆顶保留的是前k大中的最小值。比如在top K问题中,可以使用priority_queue<int, vector<int>, greater<int>>。 -
优先队列的其他用法
在处理自定义数据类型时,可以通过重载运算符来控制优先队列的排序规则。例如上面的Node结构体中,operator <的定义控制了priority_queue对Node类型元素的排序方式。
4.19 刷题更新
373. Find K Pairs with Smallest Sums
priority_queue<int> pq
在priority_queue heap的学习中我们常常会有find k pairs with smallest sum或者其他会要求最后答案在k范围中的题型,这种题型我们需要在coding中就将pq的size控制在k范围内。这不是很大的时间复杂度的改变,但是heap每次插入的时间复杂度为O(logK), 这比head每次查询顶值O(1)大很多 将pq的size控制在k的范围内能有效减少时间复杂度。