【算法】使用优先级队列(堆)解决算法题(TopK等)(C++)

文章目录

  • 1. 前言
  • 2. 算法题
    • 1046.最后一块石头的重量
    • 703.数据流中的第K大元素
  • 2.5 如何选择大根堆 与 小根堆? + 为什么选择大根堆(小根堆)?
    • 692.前K个高频单词
    • 295.数据流的中位数

1. 前言

我们知道:优先级队列是一种常用的数据结构,用于解决许多算法问题。基于堆(Heap)实现,在每次操作中能够快速找到最大或最小值

使用优先级队列的典型算法问题包括:

  • Top K 问题:查找列表中前 K 个最大或最小的元素。
  • 合并 K 个排序数组:将 K 个已排序的数组合并为一个有序数组。
  • Dijkstra 算法:在加权图中找到从起点到目标节点的最短路径。
  • Huffman 编码:使用最小堆构建前缀编码树来压缩数据。

下面会挑选一些算法题并使用优先级队列进行解题。


2. 算法题

1046.最后一块石头的重量

在这里插入图片描述
思路

  • 解法大根堆
  • 大根堆:每个节点都大于等于其子节点,则堆顶节点为最大的
    1. 将数组中所有元素加入堆中,并进行循环,直至堆为空
    2. 循环每次 取两次堆顶元素,即当前最重的两石头
    3. 将两元素差继续入堆,重复过程直至循环结束
      • 如果堆中还剩一个元素,返回该元素
      • 如果已经没有元素,返回0

代码

int lastStoneWeight(vector<int>& stones) {
    priority_queue<int> heap; // 创建大根堆
    // 将数组所有元素添加到堆中
    for(int stone : stones) heap.push(stone);

    while(heap.size() > 1)
    {
        // 每次取最大的两个数
        int a = heap.top(); heap.pop();
        int b = heap.top(); heap.pop();

        if(a > b) heap.push(a - b);
    }
    return heap.size() ? heap.top() : 0;
}

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

在这里插入图片描述

思路

  • 题意分析:根据题目,可以看出来该题是一道topK类型题
  • 解法全局变量 + 小根堆
    • 使用全局变量可以省去函数之间传参的过程,也方便编写代码
    1. 创建全局变量标记k和创建全局小根堆
      • 关于为什么选择小根堆,可以看后面的解释。
    2. 由于add函数要求添加数字后返回第k大的元素,对于构造函数KthLargest,我们直接将数组中前k大的元素插入
    3. 对于add函数,直接将val插入到堆中并判断是否堆内元素超出k个
      • 如果超出,则pop掉,后直接返回堆顶元素(即为第K大)

2.5 如何选择大根堆 与 小根堆? + 为什么选择大根堆(小根堆)?

在这里插入图片描述

代码

class KthLargest {
public:
    // 小根堆
    priority_queue<int, vector<int>, greater<int>> heap;
    int _k;

    KthLargest(int k, vector<int>& nums) {
        _k = k;
        for(int num : nums){
            heap.push(num);
            if(heap.size() > _k) heap.pop();
        } 
    }
    
    int add(int val) {
        heap.push(val);
        if(heap.size() > _k) heap.pop();
        return heap.top();
    }
};

692.前K个高频单词

在这里插入图片描述

思路

  • 题意分析:即返回数组中出现次数最多的字符串(单词)
  • 解法哈希表 + 优先级队列
    1. 哈希表统计每个单词的出现次数
    2. 根据题目要求,当单词的频率相同时,按照字典序排列,则我们自定义优先级队列的比较函数。则:
      • 当单词频率不同时,用小堆的比较方式
      • 当单词频率相同时,按照字典序,用大堆的比较方式
    3. 将哈希表中统计的前k高的 字母以及频率 加入到队列
    4. 最后返回结果,遍历堆,每次加入到结果集result中并pop即可。

代码

vector<string> topKFrequent(vector<string>& words, int k) {
    // 统计单词出现频率
    unordered_map<string, int> freq;
    for (const string& word : words) {
        freq[word]++;
    }
    
    // 自定义优先队列的比较函数
    auto cmp = [](const pair<string, int>& a, const pair<string, int>& b) {
        // 比较出现次数,如果相同则按照字母顺序
        return a.second > b.second || (a.second == b.second && a.first < b.first);
    };
    
    // 优先队列,默认是大顶堆,用于存储频率最高的 k 个单词
    priority_queue<pair<string, int>, vector<pair<string, int>>, decltype(cmp)> pq(cmp);
    
    // 遍历统计好的频率,将单词加入优先队列
    for (const auto& entry : freq) {
        pq.push(entry);
        if (pq.size() > k) {
            pq.pop(); // 如果队列大小超过 k,则弹出频率最小的单词
        }
    }
    
    // 从优先队列中取出结果
    vector<string> result(k);
    for (int i = k - 1; i >= 0; --i) {
        result[i] = pq.top().first; // 逆序存储结果
        pq.pop();
    }
    
    return result;
}

295.数据流的中位数

在这里插入图片描述

思路

  • 题意分析:题目要求实现一个类,类中包含一个构造函数、一个add函数用于添加元素、以及一个find函数

  • 解法一排序 sort
    在这里插入图片描述

    • 对于本题,使用该排序法是会超时的
  • 解法二插入排序的思想
    在这里插入图片描述

    • 插入排序思想解本题是有可能超时的,但依然需要了解这种解题思想。
  • 解法三大小堆维护
    在这里插入图片描述
    在这里插入图片描述

    • 上图解释了方法思路,具体细节看下面代码即可。

代码

class MedianFinder {
public:
    // 大小堆,左大堆,右小堆
    // 且当共有奇数个元素时,左存多一个元素
    priority_queue<int, vector<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() {
        return (left.size() == right.size()) ? (left.top() + right.top()) / 2.0 : left.top();
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/334181.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端react入门day03-react获取dom与组件通信

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 受控表单绑定 React中获取DOM 组件通信 父传子 父传子-基础实现 父传子-props说明 父传子 - 特殊的…

初创公司都应该知道的20个GPT提示词和免费的GPT工具

在不断发展的初创企业环境中&#xff0c;利用 ChatGPT 等尖端工具可以改变游戏规则。以其敏捷性和创新性而闻名的初创企业总是在寻找提高效率、创造力和竞争力的方法。ChatGPT 凭借其先进的功能&#xff0c;成为这一追求中的宝贵资源。 在这篇博文中&#xff0c;我们深入研究了…

力扣第236题——二叉树的最近公共祖先 (C语言题解)

题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以…

【轮式平衡机器人】——软硬件配置/准备

本系列以轮式平衡移动机器人为例&#xff0c;将使用基于模型设计&#xff08;MBD&#xff09;方法进行介绍&#xff0c;涉及基础硬件、软件、控制算法等多方面内容&#xff0c;结合MATLAB/Simulink的强大仿真能力和代码生成能力辅助设计&#xff01;在此过程中可以系统了解开发…

Elastic Stack(1):Elastic Stack简介

1 简介 ELK是一个免费开源的日志分析架构技术栈总称&#xff0c;官网https://www.elastic.co/cn。包含三大基础组件&#xff0c;分别是Elasticsearch、Logstash、Kibana。但实际上ELK不仅仅适用于日志分析&#xff0c;它还可以支持其它任何数据搜索、分析和收集的场景&#xf…

将 SQL Server 2022 数据库备份到 MinIO

Microsoft 在将 S3 连接器和 Polybase 添加到 SQL Server 2022 时取得了重大飞跃。因此&#xff0c;企业可以利用他们保存到对象存储中的大量数据&#xff0c;并使用它来丰富 SQL Server 表。他们还可以利用对象存储来备份 SQL Server&#xff0c;这是开放性和云原生灵活性的又…

C++类相关oj题目分享(计算日期到天数转换、日期差值、打印日期、日期累加)

文章目录 1.计算日期到天数转换题目详情代码思路 2.KY111 日期差值题目详情代码思路 3.KY222 打印日期题目详情代码 4.KY258 日期累加题目详情代码思路 1.计算日期到天数转换 传送门 题目详情 代码 #include <iostream> using namespace std; int GetDay(int year,int…

面试题16.15.珠玑妙算

前言 这两天突然发现力扣上还是有我能写出来的题的&#xff0c;虽说都是简单级别的&#xff08;以及一道中等的题&#xff09;&#xff0c;但是能写出来力扣真的太开心了&#xff0c;&#xff08;大佬把我这段话当个玩笑就行了&#xff09;&#xff0c;于是乎&#xff0c;我觉…

【C语言深度剖析——第三节(关键字3)】《C语言深度解剖》+蛋哥分析+个人理解

本文由睡觉待开机原创&#xff0c;未经允许不得转载。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff01; 目录 1.基本数据类型2.sizeof关键字 前言&#xff1a; 本期我们继续探讨关于C深度解剖这本书相关内容&#…

创业前先把刘强东这两句琢磨明白!不然大概率失败!2024最适合创业的行业!2024年普通人的创业机会在哪里

第一句&#xff0c;真正解决一个问题。 这句话表达了&#xff0c;你的项目一定是要建立在解决具体的问题上&#xff0c;而不是你觉得自己有个好点子&#xff0c;或者好产品就可以了。因为即使你的产品很好&#xff0c;服务很好&#xff0c;如果不能切实的解决某个问题&#xf…

使用pycharm连接读取orcl数据库的表

背景&#xff1a;工作需要 需求&#xff1a;使用pycharm访问远程oracle类型数据库的表&#xff0c;表中包含lob字段&#xff08;这也是个坑&#xff01;&#xff09; 麻了&#xff0c;搞了一个星期&#xff0c;终于成功了&#xff0c;真可谓是每步都有坑&#xff0c;看的文章也…

每日OJ题_算法_滑动窗口⑤_力扣904水果成篮

目录 力扣904. 水果成篮 解析及代码1&#xff08;使用容器&#xff09; 解析及代码2&#xff08;开数组&#xff09; 力扣904. 水果成篮 904. 水果成篮 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这…

禅道:从安装到使用,一篇文章带你全面了解

博客前言&#xff1a; 在这个充满竞争和快节奏的世界里&#xff0c;项目管理已经成为了许多行业的关键环节。禅道作为一种功能强大、易用的项目管理工具&#xff0c;正在被越来越多的企业和团队所采用。它不仅能帮助我们高效地管理项目&#xff0c;还能提升团队协作和沟通的效…

竞赛保研 大数据房价预测分析与可视

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 大数据房价预测分析与可视 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适合…

2023我的总结:读书、写作、运动、爱家人、学一门手艺

不知不觉中&#xff0c;2024年1月已过去大半了&#xff0c;按照惯例&#xff0c;还是对过去一年的所思所行做个简单的汇报。也希望我的一些经历&#xff0c;能给到正在做年终总结或新年规划的朋友&#xff0c;一些参考。 01 读书&#xff0c;是门槛最低的高贵 最近一段时间&am…

Jmeter对接口测试入参实现MD5加密

一、自带函数助手MD5加密 在函数助手中找到__MD5这个函数&#xff0c;第一个参数是要md5加密的值&#xff0c;第二个参数是保存加密后值的变量 在请求参数中引用该函数 发送请求可以看到密码加密了 二、beanshell脚本md5加密 在jmeter的lib目录下&#xff0c;自带commons-cod…

傲空间私有部署 Linux 指南

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 安装 docker 请下载对应的 Docker&#xff0c;安装完成后启动。Install Docker Engine on Ubu…

基于HFSS的微带线特性阻抗仿真-与基于FDTD的计算电磁学方法对比(Matlab)

基于HFSS的微带线特性阻抗仿真-与基于FDTD的计算电磁学方法对比&#xff08;Matlab&#xff09; 工程下载&#xff1a; HFSS的微带线特性阻抗仿真工程文件&#xff08;注意版本&#xff1a;HFSS2023R2&#xff09;&#xff1a; https://download.csdn.net/download/weixin_445…

定向减免!函数计算让 ETL 数据加工更简单

业内较为常见的高频短时 ETL 数据加工场景&#xff0c;即频率高时延短&#xff0c;一般费用大头均在函数调用次数上&#xff0c;推荐方案一般为攒批处理&#xff0c;高额的计算成本往往令用户感到头疼&#xff0c;函数计算推出定向减免方案&#xff0c;让 ETL数据加工更简单、更…

centos7安装nginx,按图文步骤操作

下载nginx&#xff1a; 官方网站&#xff1a;http://nginx.org/ 我这使用的版本是1.8.0版本。 1.nginx要求的安装环境 1.1、需要安装gcc的环境。 yum install gcc-c 1.2、第三方的开发包。 pcre PCRE(Perl Compatible Regular Expressions)是一个Perl库&#xff0c;包括…