给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
示例 2:
输入: nums = [1], k = 1 输出: [1]
说明:
- 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
【解法一】堆排序:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int,int> tmp;
vector<int> res;
priority_queue<pair<int,int>> q;
for(auto c : nums){
tmp[c]++;
}
for(auto it : tmp){
q.push({it.second,it.first});
}
for(int i=0;i<k;++i){
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
我们默认使用最大堆的话,如果第一个值相同,则比较第二个值。这在我的另一篇博客中有说明:
https://blog.youkuaiyun.com/zpznba/article/details/84023161
如果遇到这种情况,想要按数字升序排列输出,就需要重新定义规则,不过好在这道题并不要求。我们来动手练一下:
struct tmp2 //重写仿函数
{
bool operator() (pair<int,int> &s1, pair<int,int> &s2)
{
if(s1.first == s2.first)
return s1.second>s2.second;
return s1.second<s2.second;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int,int> tmp;
vector<int> res;
priority_queue<pair<int,int>,vector<pair<int,int> >,tmp2> q;
for(auto c : nums){
tmp[c]++;
}
for(auto it : tmp){
q.push({it.second,it.first});
}
for(int i=0;i<k;++i){
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
【解法二:桶排序】
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> m;
for (int num : nums)
++m[num];
vector<vector<int>> buckets(nums.size() + 1);
for (auto p : m)
buckets[p.second].push_back(p.first);
vector<int> ans;
for (int i = buckets.size() - 1; i >= 0 && ans.size() < k; --i) {
for (int num : buckets[i]) {
ans.push_back(num);
if (ans.size() == k)
break;
}
}
return ans;
}
};
如果元素数量相同,桶排序是无法决定次序的,因为我们是按照哈希表的顺序遍历存储到桶中的,如下图:
哈希表(可能)就长这个样子:
1 | 3 |
2 | 3 |
3 | 3 |
8 | 2 |
7 | 2 |
注意:因为unordered_map是不会对键进行排序的,所以上面的表只是其中一种可能。键完全是乱序的。
根据上面的哈希我们来模拟一下桶的样子:
3 | |
7 | 2 |
8 | 1 |
出现两次的元素 | 出现三次的元素 |
如果是这样,最后从桶的最后一个元素开始输出就应该是:1,2,3,8。
但我们想要输出的是1,2,3,7怎么办?
那就把unordered_map改成map就好了。