主页有其他数据结构内容(持续更新中)
难度: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;
}
};