LeetCode 热题 100 | 堆(二)

目录

1  什么是优先队列

1.1  优先队列与堆的关系

1.2  如何定义优先队列

1.3  如何使用优先队列

1.4  如何设置排序规则

2  347. 前 K 个高频元素

2.1  第 2 步的具体实现

2.2  举例说明

2.3  完整代码

3  215. 数组中的第 K 个最大元素 - v2


菜鸟做题,语言是 C++

1  什么是优先队列

1.1  优先队列与堆的关系

优先队列:它是一种抽象数据类型,可以看作是一个队列或栈的变体,元素按照优先级的高低排列。在 C++ 中,优先队列通常使用堆来实现。

个人理解,优先队列是对堆的底层原理的封装,谁不用谁是傻子 (bushi)

1.2  如何定义优先队列

参考博客:c++ 优先队列(priority_queue)用法详解

定义如下:

priority_queue<Type, Container, Functional>

① Type 是指数据类型,即你要装什么类型的数据。

② Container 是指容器类型,即你用什么样的容器装数据。

Container 必须是用数组实现的容器,比如:vector、deque等等,不能用 list 。STL 里面默认用的是 vector 。

③ Functional 是指比较的方式,即你希望数据之间以什么样的规则来排序。

只有当数据类型比较复杂的时候才需要设置 Functional,比如你的数据是个键值对。针对基本的数据类型,不需要设置 Functional,默认是大根堆(即谁大谁排前面)。

举例说明

假设我要让优先队列装 int 型的数据,那么就有:

priority_queue<int, vector<int>> q;

如果我不想使用默认的大根堆排序方法,则有:

priority_queue<int, vector<int>, decltype(& cmp)> q(cmp);

其中 cmp 是你自定义的排序函数,返回值是 bool 类型。

如果我想让优先队列装键值对类型的数据,则有:

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(& cmp)> q(cmp);

不过就是把数据类型换了,基本结构都是一样的。

1.3  如何使用优先队列
  • q.push(data) 插入元素
  • q.pop() 弹出队首元素
  • q.top() 获取队首元素
  • q.size() 获取队列大小
  • q.empty() 判断是否为空

以上就是优先队列的基本操作,可以看出它和栈、队列的操作是一样的,无痛学习。

1.4  如何设置排序规则

假设我要为键值对排序,因此对队列定义如下:

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(& cmp)> q(cmp);

其中,pair<int, int> 的第一个 int 是键,第二个 int 是值。要求 cmp 是一个函数指针(即函数的地址),decltype 是类型推导。

排序规则如下:

static bool cmp(pair<int, int> m, pair<int, int> n) {return m.second > n.second;
}

其中,m.second 和 n.second 分别代表键值对 m 和 n 的值。

Q:为什么要加 static?

A:因为不加会报错:

  • “error: must explicitly qualify name of member function when taking its address”
  • “错误:在取成员函数的地址时必须显式限定成员函数的名称”

为什么是 m.second > n.second?这样看起来不是谁的值更大,谁排前面吗?答:我也不知道啊。

2  347. 前 K 个高频元素

好不容易通过  215. 数组中的第 K 个最大元素  学会了堆排序,准备大展身手,结果运行超时。。

解题思路:

  1. 遍历 nums 并使用 hash 为其中的所有数字计数
  2. 遍历 hash 并使用 priority_queue 为其中的计数结果排序

2.1  第 2 步的具体实现

① 定义优先队列:

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(& cmp)> q(cmp);

为什么存储的数据类型是 pair<int, int>?因为我们要同时存储 “数字” 和它的 “个数”,否则后面把 “个数” 的顺序排出来了,却不知道这些 “个数” 对应的 “数字” 是哪些。

② 遍历 hash 并使用 priority_queue 为其中的计数结果排序:

  • 依次向 priority_queue 插入数据,但限制 priority_queue 的大小最终为 k
  • 若当前元素的 count 比队首元素的 count 大,那么弹出队首,换当前元素进去
for (auto & [num, count] : hash) {if (q.size() < k) {q.push(make_pair(num, count));} else if (q.size() == k) {if (count > q.top().second) {q.pop();q.push(make_pair(num, count));}}
}

2.2  举例说明

这里用字母只是为了方便区分,原题还是用的数字

  • 假设 nums = [a, b, b, c, c, c], k = 2
  • 易得 hash = [(a, 1), (b, 2), (c, 3)]

下面来看 priority_queue 是怎么操作的:

第 1 时刻,队列大小显然没有到达 k,因此直接插入键值对。第 2 时刻,队列大小显然也没有到达 k,因此直接插入键值对。第 3 时刻,由于席位已满,因此必须判断谁更配进入队列。由于 a 的个数被 c 的个数少,因此 a 被弹出队列为 c 让位。

注意:每当有新元素进入队列的时候,队列都会按照之前设置的排序规则 cmp 为元素重新排队。

2.3  完整代码
class Solution {
public:// 排序规则static bool cmp(pair<int, int> m, pair<int, int> n) {return m.second > n.second;}vector<int> topKFrequent(vector<int>& nums, int k) {// 计数unordered_map<int, int> hash;for (auto & n : nums) {hash[n]++;}// 排序priority_queue<pair<int, int>, vector<pair<int, int>>,decltype(& cmp)> q(cmp);for (auto & [num, count] : hash) {if (q.size() < k) {q.push(make_pair(num, count));} else if (q.size() == k) {if (count > q.top().second) {q.pop();q.push(make_pair(num, count));}}}// 处理结果vector<int> ans;while (!q.empty()) {ans.push_back(q.top().first);q.pop();}return ans;}
};

3  215. 数组中的第 K 个最大元素 - v2

模仿  347. 前 K 个高频元素  即可

class Solution {
public:static bool cmp(int a, int b) {return a > b;}int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, decltype(& cmp)> q(cmp);for (auto & n : nums) {if (q.size() < k) {q.push(n);} else if (q.size() == k) {if (n > q.top()) {q.pop();q.push(n);}}}return q.top();}
};


当你有了优先队列,谁还看堆排 (〃>皿<)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里云域名优惠口令更新(亲测有效)2024年最新

2024年阿里云域名优惠口令&#xff0c;com域名续费优惠口令“com批量注册更享优惠”&#xff0c;cn域名续费优惠口令“cn注册多个价格更优”&#xff0c;cn域名注册优惠口令“互联网上的中国标识”&#xff0c;阿里云优惠口令是域名专属的优惠码&#xff0c;可用于域名注册、续…

2024.3.23

1、使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是否…

C++ - 类和对象(上)

目录 一、类的定义 二、访问限定符 public&#xff08;公有&#xff09; protected&#xff08;保护&#xff09; private&#xff08;私有&#xff09; 三、类声明和定义分离 四、外部变量和成员变量的区别与注意 五、类的实例化 六、类对象的模型 七、类的this指针…

Angular入门问题小本本

1、console.log打印object对象显示[object object] 解决方案&#xff1a;使用JSON.stringify console.log(JSON.stringify($rootScope.MaintainDeviceInfo));2、 State ‘goDiskManagement’’ is already defined 解决方案&#xff1a;同一个项目中&#xff0c;不能定义相同…

docker 的八大技术架构(图解)

docker 的八大技术架构 单机架构 概念&#xff1a; 应用服务和数据库服务公用一台服务器 出现背景&#xff1a; 出现在互联网早期&#xff0c;访问量比较小&#xff0c;单机足以满足需求 架构优缺点&#xff1a; 优点&#xff1a;部署简单&#xff0c;成本低 缺点&#xff1…

异或问题总结

刷题的时候经常遇到异或相关的题目,虽然知道是什么意思但是做题的时候总感觉力不从心,总感觉和所学的联系不上,因此总结一些我做过的或者是经典的异或问题 什么是异或? 异或简单来说就是相同的得0,相异得1,异或有一些性质例如满足交换律,结合律,自反性等等,这些性质实际上在…

dash 初体验(拔草)

Dash简介 Dash 是一个高效简洁的 Python 框架&#xff0c;建立在 Flask、Poltly.js 以及 React.js 的基础上&#xff0c;设计之初是为了帮助前端知识匮乏的数据分析人员&#xff0c;以纯 Python 编程的方式快速开发出交互式的数据可视化 web 应用。 搭建环境 在学习 Dash 的…

11 Games101 - 笔记 - 几何(曲线与曲面)

11 几何&#xff08;曲线与曲面&#xff09; 贝塞尔曲线 定义 贝塞尔曲线&#xff1a;由控制点和线段组成的曲线&#xff0c;控制点是可拖动的支点。 如图&#xff0c;蓝色为贝塞尔曲线&#xff0c;p1, p2, p3为控制点&#xff0c;曲线和初始与终止端点相切&#xff0c;并且…

【链表】Leetcode 142. 环形链表 II【中等】

环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系…

STC89C52单片机启动--综合案例秒表

代码功能&#xff1a; 1.自动开始计数&#xff0c;一共5个数码管来显示时间。一位数码管显示0-9&#xff0c;对应分度值是0.1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1min&#xff1b;上电后自动开始计…

学习刷题-12

3.22 hw机试【双指针】 Leetcode674 最长连续递增序列 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 双指针 一个慢指针一个快指针 慢指针记录递增子序列起点&#xff0c;快指针去寻找还在当前递增子序列的最后一…

忘记密码找回流程请求拦截器-前端

目录 设置找回密码请求拦截器 1.相关参数 2.约定 代码实现 1. 实现思路 2. 实现代码 校园统一身份认证系统&#xff1a; 基于网络安全&#xff0c;找回密码、重新设置密码的流程和正常登录流程中密钥等请求头不一致。 设置找回密码请求拦截器 1.相关参数 clientId 应…