说在前面的话

博主也好长一段时间没有更新力扣的刷题系列了,今天给大家带来一些优先队列的经典题目,今天博主还是用C++给大家讲解,希望大家可以从中学到一些东西。

前言

那么这里博主先安利一下一些干货满满的专栏啦!

手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏https://blog.csdn.net/yu_cblog/category_11464817.html这里是STL源码剖析专栏,这个专栏将会持续更新STL各种容器的模拟实现。

STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482


priority_queue 优先队列

优先队列的底层实现就是数据结构的堆。其中,小顶堆可以不断更新数组里的最小值,大顶堆可以不断更新数组里的最大值,push和pop自带排序功能,经常用来解决TopK问题。

如果大家有需要数据结构堆的实现可以通过博主的传送门食用噢~

【堆】数据结构-堆的实现【超详细的数据结构教学】https://blog.csdn.net/Yu_Cblog/article/details/124944614

692.前K个高频单词

看到频率,我们很自然可以想到哈希表,我们可以用哈希表记录每个单词出现的次数。看到前K个,可以断定这是一个topK问题,我们需要用到优先队列。但是,哈希表是单向的映射,因此我们还需要用到数据结构pair,这里博主自己实现了一个pair,整体代码如下:

class Pair {
public:
Pair(string e1, int e2)
:_e1(e1), _e2(e2) {} string _e1;
int _e2; bool operator<(const Pair& p) const
{
if (_e2 != p._e2)
return this->_e2 < p._e2;
//此时两个出现次数相等
return this->_e1 > p._e1;
}
};
struct cmp
{
bool operator()(const Pair& f1, const Pair& f2)
{
return f1 < f2;
}
};
class Solution {
private:
bool is_inArr(string s, vector<Pair>arr) {
for (int i = 0; i < arr.size(); i++) {
if (arr[i]._e1 == s)return true;
}
return false;
}
public:
vector<string> topKFrequent(vector<string>& words, int k) {
vector<string>ret;
unordered_map<string, int>hash;
for (int i = 0; i < words.size(); i++) {
++hash[words[i]];
}
vector<Pair>arr;
for (int i = 0; i < words.size(); i++) {
Pair tmp(words[i], hash[words[i]]);
if (!is_inArr(words[i], arr))
arr.push_back(tmp);
}
priority_queue<Pair, vector<Pair>, cmp>pq;
//初始化优先队列
for (int i = 0; i < arr.size(); i++) {
pq.push(arr[i]);
}
while (k--) {
Pair tmp = pq.top();
pq.pop();
ret.push_back(tmp._e1);
}
return ret;
}
};

347.前K个高频元素

这题和上一题思路完全一样,这里直接给出代码:

class Pair {
public:
Pair(int e1, int e2)
:_e1(e1), _e2(e2) {} int _e1;
int _e2; bool operator<(const Pair& p) const
{
if (_e2 != p._e2)
return this->_e2 < p._e2;
//此时两个出现次数相等
return this->_e1 > p._e1;
}
};
struct cmp
{
bool operator()(const Pair& f1, const Pair& f2)
{
return f1 < f2;
}
};
class Solution {
private:
bool is_inArr(int s, vector<Pair>arr) {
for (int i = 0; i < arr.size(); i++) {
if (arr[i]._e1 == s)return true;
}
return false;
}
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int>ret;
unordered_map<int, int>hash;
for (int i = 0; i < nums.size(); i++) {
++hash[nums[i]];
}
vector<Pair>arr;
for (int i = 0; i < nums.size(); i++) {
Pair tmp(nums[i], hash[nums[i]]);
if (!is_inArr(nums[i], arr))
arr.push_back(tmp);
}
priority_queue<Pair, vector<Pair>, cmp>pq;
for (int i = 0; i < arr.size(); i++) {
pq.push(arr[i]);
}
while (k--) {
Pair tmp = pq.top();
pq.pop();
ret.push_back(tmp._e1);
}
return ret;
}
};

295.数据流的中位数

比较容易想到的思路,用一个堆,取出中间的数:

class MedianFinder {
private:
priority_queue<int>pq;
public:
MedianFinder() { } void addNum(int num) {
pq.push(num);
} double findMedian() {
priority_queue<int>pq_tmp = pq;
if (pq.size() % 2 == 0) {
for (int i = 0; i < pq.size() / 2 - 1; i++) {
pq_tmp.pop();
}
//现在接下来的两个就是要用的了
int num1 = pq_tmp.top();
pq_tmp.pop();
int num2 = pq_tmp.top();
pq_tmp.pop();
return (num1 + num2) / 2.0;
}
else {
for (int i = 0; i < pq.size() / 2; i++) {
pq_tmp.pop();
}
return pq_tmp.top();
}
}
};

这个版本是无法通过的,虽然用了优先队列很大程度降低了时间复杂度,但是因为中间有拷贝过程,开销还是很大的,这样提交会超时。

用两个优先队列实现:

直接开两个堆
queMax记录比中位数大的 -- 是个小堆 -- 可以得到queMax的最小值
queMin记录比中位数小的 -- 是个大堆 -- 可以得到queMin的最大值
插入过程中保证 -- queMin的大小和queMax一样 或者queMin大小比queMax大小大1
如果queMin过大, 把其中最大的那个数插入到queMax中去
queMax过大同理
如果最后queMin.size()==queMax.size() 则中位数就是两个堆顶的平均
如果queMin.size()==queMax.size()+1 则中位数是queMin.top()

class MedianFinder {
public:
priority_queue<int, vector<int>, less<int>> queMin;
priority_queue<int, vector<int>, greater<int>> queMax; MedianFinder() {} void addNum(int num) {
if (queMin.empty() || num <= queMin.top()) {
queMin.push(num);
if (queMax.size() + 1 < queMin.size()) {
queMax.push(queMin.top());
queMin.pop();
}
}
else {
queMax.push(num);
if (queMax.size() > queMin.size()) {
queMin.push(queMax.top());
queMax.pop();
}
}
} double findMedian() {
if (queMin.size() > queMax.size()) {
return queMin.top();
}
return (queMin.top() + queMax.top()) / 2.0;
}
};

总结

看到这里 相信大家对这几道题的解题方法已经有了一定的理解了吧?如果你感觉这篇文章对你有帮助的话,希望你可以持续关注,订阅专栏,点赞收藏都是我创作的最大动力!

( 转载时请注明作者和出处。未经许可,请勿用于商业用途 )
更多文章请访问我的主页

@背包https://blog.csdn.net/Yu_Cblog?type=blog

【算法】priority_queue在力扣题中的应用 | 力扣692 | 力扣347 | 力扣295 【超详细的注释和算法解释】的更多相关文章

  1. 【Java面试题】15 String s="Hello"; s=s+“world!”;这两行代码执行后,原始的String对象中的内容到底变了没有?String与StringBuffer的超详细讲解!!!!!

    1.Java中哪些类是不能被继承的? 不能被继承的是那些用final关键字修饰的类.一般比较基本的类型或防止扩展类无意间破坏原来方法的实现的类型都应该是final的,在java中,System,Str ...

  2. 在eclipse中使用git创建本地库,以及托管项目到GitHub超详细教程

    关于安装git的教程,由于比较简单,并且网上教程特别多,而且即使不按照网上教程,下载好的windows版本git,安装时候一路默认设置就行. 安装好之后,在桌面上有git图标:右键菜单中有Git Ba ...

  3. 【经验】 Java BigInteger类以及其在算法题中的应用

    [经验] Java BigInteger类以及其在算法题中的应用 标签(空格分隔): 经验 本来在刷九度的数学类型题,有进制转换和大数运算,故而用到了java BigInteger类,使用了之后才发现 ...

  4. Java在算法题中的输入问题

    Java在算法题中的输入问题 在写算法题的时候,经常因为数据的输入问题而导致卡壳,其中最常见的就是数据输入无法结束. 1.给定范围,确定输入几个数据 直接使用普通的Scanner输入数据范围,然后使用 ...

  5. 前端与算法 leetcode 26. 删除排序数组中的重复项

    目录 # 前端与算法 leetcode 26. 删除排序数组中的重复项 题目描述 概要 提示 解析 算法 # 前端与算法 leetcode 26. 删除排序数组中的重复项 题目描述 26. 删除排序数 ...

  6. 动手实现 LRU 算法,以及 Caffeine 和 Redis 中的缓存淘汰策略

    我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 那天我在 LeetCode 上刷到一道 LRU 缓存机制的问题, ...

  7. 算法训练 Hankson的趣味题

    算法训练 Hankson的趣味题   时间限制:1.0s   内存限制:64.0MB        问题描述 Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Han ...

  8. Expm 10_2 实现Ford-Fulkerson算法,求出给定图中从源点s到汇点t的最大流,并输出最小割。

    package org.xiu68.exp.exp10; import java.util.ArrayDeque; import java.util.ArrayList; import java.ut ...

  9. 算法笔记(c++)--c++中碰到的一些用法

    算法笔记(c++)--c++中碰到的一些用法 toupper(xxx)可以变成大写; tolower(xx)小写 isalpha(xxx)判断是不是字母 isalnum(xx)判断是不是数字 abs( ...

  10. 在洛谷3369 Treap模板题 中发现的Splay详解

    本题的Splay写法(无指针Splay超详细) 前言 首先来讲...终于调出来了55555...调了整整3天..... 看到大部分大佬都是用指针来实现的Splay.小的只是按照Splay的核心思想和原 ...

随机推荐

  1. Codeforces Round #704 (Div. 2) A~E

    比赛链接:https://codeforces.com/contest/1492 1492A.Three swimmers 题意: 有三名游泳的人,他们分别需要 \(a,b,c\) 分钟才能在一个游泳 ...

  2. CodeForces-339B-Xenia and Ringroad (循环队列,水题)

    Xenia lives in a city that has n houses built along the main ringroad. The ringroad houses are numbe ...

  3. 4.0 《数据库系统概论》数据库安全性详解---(存取控制、DAC&MAC、视图机制、审计Audit....)

    前言 本篇文章学习书籍:<数据库系统概论>第5版 王珊 萨师煊编著 视频资源来自:数据库系统概论完整版(基础篇+高级篇+新技术篇) 由于 BitHachi 学长已经系统的整理过本书了,我在 ...

  4. L3-013 非常弹的球 (30 分) (math)

    刚上高一的森森为了学好物理,买了一个"非常弹"的球.虽然说是非常弹的球,其实也就是一般的弹力球而已.森森玩了一会儿弹力球后突然想到,假如他在地上用力弹球,球最远能弹到多远去呢?他不 ...

  5. 如虎添翼!高德地图+Serverless 护航你的假日出行

    ​ 作者 | 刘金龙(福辰) 高德团队 引言 ​ "前方事故多发地段,请注意保持车距..." "您已疲劳驾驶,请注意休息..." "前方经过泰山旅游景 ...

  6. C#语言 十大经典排序算法动画与解析!(动态演示+代码)(java改写成C# )

    以下内容是根据 https://www.cnblogs.com/fivestudy/p/10212306.html   进行改写 排序算法是<数据结构与算法>中最基本的算法之一. 排序算法 ...

  7. python爬虫-豆瓣电影top250

    一.python爬虫简介1.什么是爬虫:网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本.由于互联网数据的多样性和资源的有限性,根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略 ...

  8. python常见面试题讲解(九)字符个数统计

    题目描述 编写一个函数,计算字符串中含有的不同字符的个数.字符在ACSII码范围内(0~127),换行表示结束符,不算在字符里.不在范围内的不作统计.注意是不同的字符 输入描述: 输入N个字符,字符在 ...

  9. 无法访问Github仓库的极简治标法

    技术背景 由于IP原因,国内的IP访问Github仓库的时候会经常遇到一些困难,甚至存在无法Ping通的情况.尝试过FastGithub等方案,但还是会遇到各种各样的问题,导致情况越来越复杂. 但是转 ...

  10. [转帖]SQL Server 2008~2022版本序列号/密钥/激活码 汇总

    https://www.cnblogs.com/cqpanda/p/16148822.html SQL Server 2022# Enterprise: J4V48-P8MM4-9N3J9-HD97X ...