题目描述
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
输入: nums = [1], k = 1
输出: [1]
说明:
- 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
- 你可以按任意顺序返回答案。
题目链接: https://leetcode-cn.com/problems/top-k-frequent-elements/
思路1
用哈希表统计每个元素出现的次数,然后根据次数创建一个新的二维数组 v,下标为每个元素出现的次数。例如,v[cnt] = [1,2] 的含义是 1, 2 分别出现了 cnt 次,然后从后往前遍历二维数组 v,如果 v[i] 不空,就将 v[i] 中的元素放进答案中,直到答案中已经包含了 k 个元素。代码如下:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
if(nums.empty()) return {};
unordered_map<int, int> hash;
for(int i=0; i<nums.size(); i++){
hash[nums[i]]++;
}
vector<vector<int>> v(nums.size()+1);
auto it = hash.begin();
for(; it!=hash.end(); it++){
int key = it->first;
int value = it->second;
v[value].push_back(key);
}
vector<int> ans;
for(int i=v.size()-1; i>=0 && ans.size()<k; i--){
if(!v[i].empty()){
for(int j=0; j<v[i].size(); j++) ans.push_back(v[i][j]);
}
}
return ans;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
思路2
思路 2 整体上和思路 1 是一样的,首先用哈希表统计各元素出现的频率,然后使用小根堆来替代思路 1 中的二维数组,可以使用 stl 中的优先队列 priority_queue 来模拟小根堆。小根堆的定义为priority_queue<pair<int, int>> q
,pair 的第二个值为元素,第一个值为该元素出现的频率,因为 priority_queue 默认按照 pair 的第一个值降序排序。将优先队列中的元素出队列,并将队头节点pair 的第二个值放进答案中(第二个值就是数组中的元素,第一个值为出现次数)。代码如下:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
if(nums.empty()) return {};
unordered_map<int, int> hash;
for(int i=0; i<nums.size(); i++){
hash[nums[i]]++;
}
priority_queue<pair<int, int>> q;
auto it = hash.begin();
for(; it!=hash.end(); it++){
q.push(make_pair(it->second, it->first));
}
vector<int> ans;
while(!q.empty() && ans.size()<k){
auto item = q.top(); q.pop();
ans.push_back(item.second);
}
return ans;
}
};
关于按照 pair 中第一个元素升序还是降序排列的问题可以参考这篇文章。
- 时间复杂度:O(nlogk)
- 空间复杂度:O(n)