深度剖析优先级队列:堆的搭建至解题策略全方位解读

深度解析优先级队列:堆的构建到解题策略的全面解读

在这里插入图片描述

算法 相关知识点 可点击 以下链接学习 共同进步!
双指针
滑动窗口
二分查找
前缀和
位运算
模拟
链表
哈希表
字符串模拟
栈模拟(非单调栈)

优先级队列(Priority Queue),其本质是支持动态插入与按优先级弹出操作的堆结构,是解决这类问题的高效工具。本文将从底层堆的实现出发,逐步构建优先级队列的完整解题框架,并结合高频题目,助你掌握其在算法实战中的应用。

请添加图片描述

Alt

文章目录

  • 一、铺垫知识
    • 1.1 堆排序(Heap Sort)
    • 1.2 快速选择(QuickSelect)算法解Top K问题
    • 3.Tok问题中,大根堆与小根堆的使用场景
    • 1046. 最后一块石头的重量
    • 703. 数据流中的第K大元素
    • 692. 前K个高频单词
    • 295. 数据流的中位数

本专题借助优先级队列解决问题。首先需了解堆与快速选择算法解Top K问题,明确大根堆与小根堆的适用场景及选择依据。

在这里插入图片描述

一、铺垫知识

1.1 堆排序(Heap Sort)

堆排序利用最大堆(Max Heap)最小堆(Min Heap)实现排序。

可参考文章:理解堆的特性与应用

1.2 快速选择(QuickSelect)算法解Top K问题

用选择排序解Top K(Tok)问题时,无需全排序,仅需K次选择找第K大(小)元素
将上述步骤整合
快速选择排序整合
若用选择排序解Top K问题,仅需K次选择过程找第K大(或K小)元素。

3.Tok问题中大根堆与小根堆的场景

  • 大根堆(Max Heap):
  • 用于取最大元素或Top K 最小元素(维护K个最小元素,堆顶最大)。
  • 示例:找 前K小(维护大小为K的大根堆)。
  • 小根堆(Min Heap):
  • 用于取最小元素或Top K 最大元素(维护K个最大元素,堆顶最小)。
  • 示例:找 前K大(维护大小为K的小根堆)

1046. 最后一块石头的重量

题目】:1046. 最后一块石头的重量

在这里插入图片描述

算法思路

利用堆的特性,反复取出当前最大两值碰撞,将结果插回堆。

代码实现

class Solution {
public:
    int lastStoneWeight(vector<int>& stones) {
        int n = stones.size();
        priority_queue<int> pq;
        for (auto x : stones) pq.push(x);
        while (pq.size() > 1) {
            int x = pq.top(); pq.pop();
            int y = pq.top(); pq.pop();
            if (x > y) pq.push(x - y);
        }
        return pq.size() ? pq.top() : 0;
    }
};

703. 数据流中的第K大元素

题目】:703. 数据流中的第K大元素

在这里插入图片描述

算法思路

此题为Top K问题,用小根堆。插入新元素时,若堆大小超K,移除堆顶(最小)。插入时,堆自动调整,堆顶为K大元素中最小。若插入元素大于堆顶,替换;否则不变。动态维护第K大。

代码实现

class KthLargest {
public:
    priority_queue<int, vector<int>, greater<int>> pq;
    int k;
    KthLargest(int k, vector<int>& nums) {
        this->k = k;
        for (auto x : nums) {
            pq.push(x);
            if (pq.size() > k) pq.pop();
        }
    }

    int add(int val) {
        pq.push(val);
        if (pq.size() > k) pq.pop();
        return pq.top();
    }
};

692. 前K个高频单词

题目】:692. 前K个高频单词

在这里插入图片描述

算法思路

本题用堆解Top K,需选堆结构。有两排序:频次用小根堆,保证堆顶是K个中频次最低;字典序(频次同)用大根堆,保证同频次降序。因字典序是频次子集,比较函数中加if实现多条件。结果倒序,用小根堆维护前K高频。

代码实现

class Solution {
public:
    using PSI = pair<string, int>;
    struct Cmp {
        bool operator()(const PSI& a, const PSI& b) {
            if (a.second == b.second) {
                return a.first < b.first;
            }
            return a.second > b.second;
        }
    };

    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string, int> cnt;
        for (auto& str : words) cnt[str]++;
        priority_queue<PSI, vector<PSI>, Cmp> pq;
        for (auto& p : cnt) {
            pq.push(p);
            if (pq.size() > k) pq.pop();
        }
        vector<string> res(k);
        for (int i = k - 1; i >= 0; i--) {
            res[i] = pq.top().first;
            pq.pop();
        }
        return res;
    }
};

295. 数据流的中位数

题目】:295. 数据流的中位数

在这里插入图片描述

算法思路

数据量大时前两法可能超时,用大小堆维护。根据m==n和m>n(m=n+1)分类,num<x放大根堆,否则放小根堆。调整维护。

代码实现

class MedianFinder {
public:
    priority_queue<int> left; // 大根堆
    priority_queue<int, vector<int>, greater<int>> right; // 小根堆

    MedianFinder() {}

    void addNum(int num) {
        if (left.size() == right.size()) {
            if (left.empty() || num <= left.top()) {
                left.push(num);
            } else {
                right.push(num);
                left.push(right.top());
                right.pop();
            }
        } else {
            if (num <= left.top()) {
                left.push(num);
                right.push(left.top());
                left.pop();
            } else {
                right.push(num);
            }
        }
    }

    double findMedian() {
        if (left.size() == right.size()) {
            return (left.top() + right.top()) / 2.0;
        } else {
            return left.top();
        }
    }
};

细节

访问left.top()前检查堆非空,如条件left.empty() || num <= left.top()

在这里插入图片描述
快来和小二开启算法之旅!关注我,一同破解算法难题,探索实用有趣知识,开启编程冒险!

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/12972.html

(0)
LomuLomu
上一篇 1天前
下一篇 1天前

相关推荐

  • 2025年最新IDEA激活码分享:永久破解IDEA至2099年(附详细教程)

    适用于JetBrains全家桶的破解方法 今天给大家带来一个好消息!经过实测,我们找到了最新版IDEA的完美破解方案,支持将使用期限延长至2099年。先上破解成功的截图,让大家放心: 这个方法不仅适用于最新版IDEA,也兼容PyCharm、DataGrip、Goland等JetBrains全家桶软件,无论你使用什么操作系统或版本,都能轻松搞定! 第一步:获取…

    IDEA破解教程 2025 年 7 月 6 日
    5400
  • 2025年最新PyCharm激活码与永久破解教程(支持2099年)

    全面支持Jetbrains全家桶的破解方案 今天给大家带来一个重磅福利!无论你使用的是PyCharm、IDEA、DataGrip还是Goland,这套方法都能完美激活。先上效果图,可以看到我的PyCharm已经成功破解到2099年了! 下面将详细介绍如何一步步实现PyCharm永久激活,这个方法同样适用于旧版本! Windows/Mac/Linux全平台支持…

    PyCharm激活码 2025 年 7 月 8 日
    8700
  • 数据结构(Java版)第二期:包装类和泛型

    目录 一、包装类 1.1. 基本类型和对应的包装类 1.2. 装箱和拆箱 1.3. 自动装箱和自动拆箱 二、泛型的概念 三、引出泛型 3.1. 语法规则 3.2. 泛型的优点 四、类型擦除 4.1. 擦除的机制 五、泛型的上界 5.1. 泛型的上界的定义 5.2. 语法规则 六、泛型方法 6.1. 定义语法 6.2. 交换方法的实例 七、通配符 包装类和泛型…

    2025 年 1 月 1 日
    27000
  • 2025年最新DataGrip永久破解教程(附激活码/注册码)🔥

    还在为DataGrip的激活问题发愁吗?😫 本教程将手把手教你如何轻松破解DataGrip至2099年!适用于Windows、Mac等全平台,亲测有效!💯 本方法支持JetBrains全家桶(IDEA、PyCharm、Goland等)哦~ 先来看看破解成功的效果吧!👇 有效期直接拉到2099年,简直不要太爽! 🚀 准备工作 下载DataGrip安装包 还没安…

    2025 年 6 月 16 日
    54200
  • 2025年最新IDEA激活码永久破解教程(支持JetBrains全家桶)

    前言 本教程适用于IntelliJ IDEA、PyCharm、DataGrip、GoLand等JetBrains全系列开发工具,让你轻松破解到2099年! 先看最新IDEA版本破解成功的效果图,有效期已延长至2099年,完美解决开发者的后顾之忧! 准备工作 下载IDEA安装包 如果已经安装可跳过此步骤 访问JetBrains官网:https://www.je…

    2025 年 5 月 9 日
    27700

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信