Priority Queue 优先队列 Leetcode

272 阅读3分钟

基础知识

📺 b站视频链接

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)

困难难度 (Hard)

  • 239. Sliding Window Maximum
    👉 这道题用 priority_queue 实在是太巧妙了。

  • 480. Sliding Window Median
    👉 Meta 30天挑战中遇到的题。

  • 295. Find Median from Data Stream
    👉 通过维护两个堆来实现,分别是大顶堆和小顶堆。第一次只维护了一个大顶堆,结果丢失了关键信息。后来发现,维护两个堆(大顶堆 + 小顶堆)可以确保更好地获取中位数。单独维护一个堆会导致信息丢失,无法完整获取数据分布。

  • 407. Trapping Rain Water II 👉 通过最小堆从边界向内扩散,每次以当前最低边界决定水位高度,并更新周围未访问的邻居:
    若邻居高度低于当前边界,则视为能接水。最小堆推进(高度更新为当前边界高度);否则保留原高度。
    这一过程模拟“水往低处流”的灌水逻辑,同时有效防止遗漏中间洼地。

代码细节和注意事项

  1. 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个最大数中的最小值
    
  2. 做题时注意细节
    如果要求第 k 大元素,则要使用小顶堆,这样可以保证堆顶保留的是前 k 大中的最小值。比如在top K问题中,可以使用 priority_queue<int, vector<int>, greater<int>>

  3. 优先队列的其他用法
    在处理自定义数据类型时,可以通过重载运算符来控制优先队列的排序规则。例如上面的 Node 结构体中,operator < 的定义控制了 priority_queueNode 类型元素的排序方式。

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的范围内能有效减少时间复杂度。