Given a non-empty array of integers, return the k most frequent elements.
For example,
Given [1,1,1,2,2,3]
and k = 2, return [1,2]
.
Note:
- You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
- Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
这道题是找数组中前K个数量最多的元素,题目难度为Medium。
比较直观的想法是用Hash Table统计元素个数,然后用堆来找出前K个数量最多的元素。priority_queue默认是大根堆,所以可以将<计数-元素>对直接存入堆中。具体代码:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> hash;
priority_queue<pair<int,int>> heap;
vector<int> ret;
for(int num:nums)
hash[num]++;
for(auto it:hash)
heap.push(make_pair(it.second, it.first));
for(int i=0; i<k; ++i) {
ret.push_back(heap.top().second);
heap.pop();
}
return ret;
}
};
虽然解决了题目,但是时间复杂度达到了O(nlogn),因为建堆的时间复杂度是O(logn),题目要求时间复杂度优于 O(nlogn),因此还需要优化。这里可以用小根堆取代大根堆,在堆元素超过K时,删除堆顶元素,因为它不可能是数量最多的K个元素之一,遍历完所有数组元素之后堆中剩下的K个元素即是所求结果。优化后时间复杂度为O(nlogK)。具体代码:
class Solution {
typedef pair<int, int> data;
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> hash;
priority_queue<data, vector<data>, greater<data>> heap;
vector<int> ret;
for(int num:nums)
hash[num]++;
for(auto it:hash) {
heap.push(make_pair(it.second, it.first));
if(heap.size() > k) heap.pop();
}
while(!heap.empty()) {
ret.push_back(heap.top().second);
heap.pop();
}
return ret;
}
};
另外看到有人通过桶排序来解决问题,顺便介绍一下这种方法。桶排序的基本思想就不讲了,不清楚的同学可以问度娘。假设数组共有N个元素,用编号为1~N的N个桶分别存储个数为桶号个的元素,统计完成后从第N个桶开始从后向前依次取桶中元素,直至取够K个元素即得到了结果。具体代码:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> hash;
vector<vector<int>> buckets(nums.size()+1);
vector<int> ret;
for(int num:nums)
hash[num]++;
for(auto it:hash)
buckets[it.second].push_back(it.first);
for(int i=buckets.size()-1; i>0; --i) {
for(auto num:buckets[i]) {
ret.push_back(num);
if(ret.size() == k) return ret;
}
}
return ret;
}
};
题目中没有说明类似[1, 1, 1, 2, 2, 3, 3],K=2这种情况下返回[1, 2]还是[1, 3],就先当做都正确处理吧。