347. 前 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

 

posted @ 2021-01-27 20:38  Uitachi  阅读(67)  评论(0编辑  收藏  举报