LeetCode 347. 前 K 个高频元素

主页有其他数据结构内容(持续更新中)

难度:Medium

代码:

法一:桶排序

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //  用哈希表统计每个元素的出现次数
        unordered_map<int, int> dic;
        //  统计出现次数最多的元素出现了多少次,方便后续的桶排序建桶
        int maxCount = 0;
        for (auto c : nums) {
            dic[c]++;
            maxCount = max(maxCount, dic[c]);
        }
        //  建桶
        //  这里要建的桶的大小是maxCount+1,因为下标为maxCount的位置需要放对应元素
        vector<vector<int>> buckets(maxCount + 1);
        for(auto pair : dic) {
            //  把出现次数当作下标,把所有出现次数相同的元素放在同一个数组里
            buckets[pair.second].emplace_back(pair.first);
        }
        vector<int> res;
        //  从后往前遍历,因为桶是增序排列,出现次数最多的元素都在后面
        for(int i = maxCount; i >= 0 && res.size() < k; i--) {
            for(auto j : buckets[i]) {
                res.emplace_back(j);
                if(res.size() == k) {
                    break;
                }
            }
        }
        return res;
    }
};

法二:优先队列+小顶堆

//  时间复杂度:O(nlogk)
//  空间复杂度:O(n)
class Solution {
public:
    //  小顶堆
    class cmp {
    public:
        bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
            //  增序排列(优先队列的cmp函数与常规cmp函数相反)
            return lhs.second > rhs.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //  统计元素出现频率
        //  map<nums[i],对应出现的次数>
        unordered_map<int, int> dic; 
        for (auto c : nums) {
            dic[c]++;
        }

        //  对频率排序
        //  定义一个小顶堆,大小为k
        priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> pri_que;

        //  用固定大小为k的小顶堆,扫面所有频率的数值
        for (auto it = dic.begin(); it != dic.end(); it++) {
            pri_que.push(*it);
            //  如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
            //  这里体现了为什么要建立小顶堆而不是大顶堆
            //  由于我们要找的是前k个最大值,而小顶堆的top是最小元素,可以被pop掉
            if (pri_que.size() > k) { 
                pri_que.pop();
            }
        }

        vector<int> result;
        while (!pri_que.empty()) {
            result.emplace_back(pri_que.top().first);
            pri_que.pop();
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值