一、题目
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

 

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

 

提示:

    1 <= nums.length <= 10^5
    k 的取值范围是 [1, 数组中不相同的元素的个数]
    题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

 

进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小
二、思路
  • 第一种:使用map来统计每一个数字出现的次数,再使用一个堆来保存k个最大的次数。复杂度O(n+nlogk)
  • 第二种:使用桶排序的思想,根据最大的出现次数创建多少个桶,每个桶里面放着出现该次数的数,最后倒序遍历桶即可。复杂度O(n)
三、代码
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        vector<int> ans;
        for (auto val : nums) mp[val]++;
        auto cmp = [](pair<int, int>& a, pair<int, int>& b){return a.second > b.second;};
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> q(cmp);
        for (auto [one, tow] : mp) {
            if (q.size() == k) {
                //已经有k个了进行比较 由于是小根堆比较最小的在开头
                if (q.top().second < tow) {
                    q.pop();
                    q.emplace(one, tow);
                }
            } else {
                q.emplace(one, tow);
            }
        }
        while (!q.empty()) {
            ans.push_back(q.top().first);
            q.pop();
        }
   
        return ans;
    }
};
  • 桶排序
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        vector<int> ans;
        int max_size = 0;
        for (auto val : nums) {
            mp[val]++;
            max_size = max(max_size, mp[val]);
        }
        vector<vector<int>> bucket(max_size + 1);
        for (auto [one, tow] : mp) {
            bucket[tow].push_back(one);
        }
        //倒序遍历桶
        for (int i = max_size; i >= 1 && ans.size() < k; i--) {
            for (auto val : bucket[i]) {
                ans.push_back(val);
                if (ans.size() == k) break;
            }
        }
        return ans;
    }
};