【优选算法】优先级队列 {经验总结:优先级队列解决TopK问题,利用大小堆维护数据流中的中位数;相关编程题解析}

本文主要是介绍【优选算法】优先级队列 {经验总结:优先级队列解决TopK问题,利用大小堆维护数据流中的中位数;相关编程题解析},希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、经验总结

优先级队列(堆),常用于在集合中筛选最值或解决TopK问题。

提示:对于固定序列的TopK问题,最优解决方案是快速选择算法,时间复杂度为O(N)比堆算法O(NlogK)更优;而对于动态维护数据流中的TopK,最优解决方案是堆算法,每次添加数据后筛选,时间复杂度为O(logK)比快速选择算法O(N)更优;

优先级队列如何解决TopK问题?

  1. 创建一个大小为K的堆
  2. 循环
    1. 将数组中的元素依次进堆
    2. 判断堆中的元素个数是否大于K,如果大于K就pop弹出堆顶元素
  3. 将数组中的所有元素全部筛选一遍后,堆中剩余的K个元素就是最大(小)的K个元素

TopK问题选用大根堆还是小根堆?

  • 如果要选出最大的K个数,就选用小根堆;
  • 如果要选出最小的K个数,就选用大根堆;

利用大小堆维护数据流中的中位数

  1. 创建一个大堆left用于存储数据流的前一半(升序),一个小堆right用于存储后一半
  2. 控制left的元素个数m和right的元素个数n满足:m==n或m==n+1
  3. 数据流的中位数:当m==n时,mid=(left.top()+right.top())/2;当m==n+1时,mid=left.top();
  4. 新增元素:将新元素与left.top()(或right.top())比较,决定加入left还是right。完成插入后,记得调整两个堆的元素个数使其满足规则。

二、相关编程题

2.1 最后一块石头的重量

题目链接

1046. 最后一块石头的重量 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

利用堆结构筛选最大值

编写代码

class Solution {
public:int lastStoneWeight(vector<int>& stones) {priority_queue<int> heap;for(auto e : stones) heap.push(e);while(heap.size() >= 2){int s1 = heap.top();heap.pop();int s2 = heap.top();heap.pop();if(s1 > s2) heap.push(s1-s2);}if(heap.size() == 0) return 0;else return heap.top();}
};

2.2 数据流中的第 K 大元素

题目链接

703. 数据流中的第 K 大元素 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述
这道题更适合使用堆解决,因为add函数插入一个数字后返回当前数据中的第K大的元素,如果使用快速选则算法,复杂度为O(N);而使用堆算法,复杂度为O(logK)

编写代码

class KthLargest {priority_queue<int, vector<int>, greater<int>> _heap;int _k;
public:KthLargest(int k, vector<int>& nums) {_k = k;for(auto e : nums) add(e);}int add(int val) {_heap.push(val);if(_heap.size() > _k)_heap.pop();return _heap.top();}
};

2.3 前K个高频单词

题目链接

692. 前K个高频单词 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class Solution {typedef pair<string, int> PSI;struct Cmp{bool operator()(const PSI &left, const PSI &right){if(left.second != right.second) //出现频次不同,选出高频单词,按照小根堆的方式排列return left.second > right.second;elsereturn left.first < right.first; //出现频次相同,按字典序排序,按照大根堆的方式排列}};
public:vector<string> topKFrequent(vector<string>& words, int k) {unordered_map<string, int> hash;priority_queue<PSI, vector<PSI>, Cmp> heap;vector<string> ret(k);//统计所有单词的出现频次for(auto &str:words){++hash[str];} //用一个大小为k的堆筛选TopKfor(auto &psi:hash){heap.push(psi);if(heap.size() > k)heap.pop();}//将结果倒着放入数组for(int i = k-1; i >= 0; --i){ret[i] = heap.top().first;heap.pop();}return ret;}
};

2.4 数据流的中位数

题目链接

295. 数据流的中位数 - 力扣(LeetCode)

题目描述

在这里插入图片描述

算法原理

在这里插入图片描述

编写代码

class MedianFinder {priority_queue<int> left; //大根堆priority_queue<int, vector<int>, greater<int>> right; //小根堆
public:MedianFinder() {}void addNum(int num) {if(left.size() > right.size()) //m > n{int x = left.top();if(num <= x){left.push(num);left.pop();right.push(x);}else{right.push(num);}}else //m == n{int y = right.empty()? 0:right.top();if(right.empty() || num < y){left.push(num);}else{right.push(num);right.pop();left.push(y);}}}double findMedian() {if(left.size() > right.size()) //m > nreturn (double)left.top();else //m == nreturn (left.top()+right.top())/2.0;}
};

这篇关于【优选算法】优先级队列 {经验总结:优先级队列解决TopK问题,利用大小堆维护数据流中的中位数;相关编程题解析}的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1032775

相关文章

mybatis和mybatis-plus设置值为null不起作用问题及解决

《mybatis和mybatis-plus设置值为null不起作用问题及解决》Mybatis-Plus的FieldStrategy主要用于控制新增、更新和查询时对空值的处理策略,通过配置不同的策略类型... 目录MyBATis-plusFieldStrategy作用FieldStrategy类型每种策略的作

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python Jupyter Notebook导包报错问题及解决

《PythonJupyterNotebook导包报错问题及解决》在conda环境中安装包后,JupyterNotebook导入时出现ImportError,可能是由于包版本不对应或版本太高,解决方... 目录问题解决方法重新安装Jupyter NoteBook 更改Kernel总结问题在conda上安装了

pip install jupyterlab失败的原因问题及探索

《pipinstalljupyterlab失败的原因问题及探索》在学习Yolo模型时,尝试安装JupyterLab但遇到错误,错误提示缺少Rust和Cargo编译环境,因为pywinpty包需要它... 目录背景问题解决方案总结背景最近在学习Yolo模型,然后其中要下载jupyter(有点LSVmu像一个

Goland debug失效详细解决步骤(合集)

《Golanddebug失效详细解决步骤(合集)》今天用Goland开发时,打断点,以debug方式运行,发现程序并没有断住,程序跳过了断点,直接运行结束,网上搜寻了大量文章,最后得以解决,特此在这... 目录Bug:Goland debug失效详细解决步骤【合集】情况一:Go或Goland架构不对情况二:

解决jupyterLab打开后出现Config option `template_path`not recognized by `ExporterCollapsibleHeadings`问题

《解决jupyterLab打开后出现Configoption`template_path`notrecognizedby`ExporterCollapsibleHeadings`问题》在Ju... 目录jupyterLab打开后出现“templandroidate_path”相关问题这是 tensorflo

如何解决Pycharm编辑内容时有光标的问题

《如何解决Pycharm编辑内容时有光标的问题》文章介绍了如何在PyCharm中配置VimEmulator插件,包括检查插件是否已安装、下载插件以及安装IdeaVim插件的步骤... 目录Pycharm编辑内容时有光标1.如果Vim Emulator前面有对勾2.www.chinasem.cn如果tools工

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH