347. 前 K 个高频元素
题目
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
分析
1.统计每个数字出现的频率,用map哈希即可
2.找 Top K 问题,用优先级队列
关键是用小根堆还是大根堆,其实我的第一反应是建立大根堆,最后取k大根堆的头K个即可,这样时间复杂度是O(nlogn).
如果采用小根堆,每次维护K个元素的小根堆,这样每次排序的时间复杂度是 logK,总体时间复杂度就降到了O(nlogk)。具体来说就是,每次弹出小根堆根结点,插入元素。这样最后剩下的就是最大的K个元素,最后还需要将这个优先级队列弹出后再逆置。
代码
自己一开始建立大根堆 O(nlogn).
1 class Solution { 2 public: 3 //大根堆 4 class myComp{ 5 public: 6 bool operator()(pair<int,int>p1,pair<int,int>p2){ 7 return p1.second < p2.second; 8 } 9 }; 10 11 vector<int> topKFrequent(vector<int>& nums, int k) { 12 //统计每个数字出现的频率,用map 13 unordered_map<int,int>mp; 14 for(int i = 0;i < nums.size();i++){ 15 mp[nums[i]]++; 16 } 17 18 priority_queue<pair<int,int>,vector<pair<int,int>>,myComp> pri_que; 19 for (auto it = mp.begin(); it != mp.end(); it++) { 20 pri_que.push(*it); 21 } 22 vector<int>res; 23 for(int i = 0;i < k;i++){ 24 res.push_back(pri_que.top().first); 25 pri_que.pop(); 26 } 27 return res; 28 } 29 };
建立个数为 K 的小根堆O(nlogk)
class Solution { public: class myComp{ public: bool operator()(const pair<int,int> &p1,const pair<int,int> &p2){ return p1.second > p2.second; } }; vector<int> topKFrequent(vector<int>& nums, int k) { //1.用map哈希存每个元素出现的频率 unordered_map<int,int>mp; for(int i = 0;i < nums.size();i++){ mp[nums[i]]++; } //2.建立小根堆 priority_queue<pair<int,int>, vector<pair<int,int>>,myComp>pri_que; for(auto it = mp.begin();it != mp.end();it++){ pri_que.push(*it); if(pri_que.size() > k) pri_que.pop(); } //3.将结果存入res,再逆置 vector<int>res; for(int i = 0;i < k;i++){ res.push_back(pri_que.top().first); pri_que.pop(); } reverse(res.begin(),res.end()); return res; } };
总结:
1. top K 问题用优先级队列, 如果求前 K个最大值,用小根堆。若求前K个最小值,用大根堆。
2. 大根堆的实现,自己写比较类时,要注意 left < right 是 大根堆,这一点与sort中的自定义比较函数正好相反
3.相关优先级队列的知识 https://blog.csdn.net/weixin_36888577/article/details/79937886