题目描述
给定一个非空整数数组,请返回出现次数最多的 k 个数。
注意:
- 你可以假定 k 一定是合法的,即 1≤k≤ 数组中不同元素的个数,且排名在第 k 位和排名在第 k+1 位的数,出现次数不同;
- 你的算法一定要比 O(nlogn) 快;
样例
给定 [1,1,1,2,2,3] 并且 k = 2,
返回 [1,2].
算法
(哈希表,计数排序) O(n)
首先用哈希表统计出所有数出现的次数。
由于所有数出现的次数都在 1 到 n 之间,所以我们可以用计数排序的思想,统计出次数最多的前 k 个元素的下界。然后将所有出现次数大于等于下界的数输出。
时间复杂度分析:用哈希表统计每个数出现次数的计算量是 O(n),计数排序的计算量是 O(n),最终用下界过滤结果的计算量也是 O(n),所以总时间复杂度是 O(n)。
C++ 代码
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> hash;
vector<int> res;
for (int x : nums) hash[x] ++;
int n = nums.size();
vector<int>s(n + 1, 0);
for (auto &p : hash) s[p.second] ++ ;
int i = n, t = 0;
while (t < k) t += s[i -- ];
for (auto &p : hash)
if (p.second > i)
res.push_back(p.first);
return res;
}
};
class Solution { public: static bool comp(const pair<int,int> &a, const pair<int,int> &b) { return a.second > b.second; } vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map<int,int> umap; for (auto c : nums) umap[c]++; vector<pair<int,int>> b; for (auto x : umap) b.push_back(x); sort(b.begin(),b.end(),comp); vector<int> res; for (int i = 0; i < k; i++) res.push_back(b[i].first); return res; } };
前面统计每个元素出现次数可以理解,到 for (auto &p : hash) s[p.second] ++ ;这块没理解
p.second表示的是出现次数,s是计数数组,比如一个元素出现三次,s[3]++,表示有一个元素出现了三次
hash是统计每个元素出现次数,s是统计出现次数的个数,比如[1,1,2,2,3] s[2]=2,s[1]=1。后面操作是,从出现次数最大的,累加到k
如果要求返回值一定按照freq输出的话 除了map+pq有没有别的做法啊?每次写pq的cmp都会写错,想知道能不能绕过自定义这些东西……
在用priority_queue的时候,可以用STL里的pair[HTML_REMOVED],它默认以first为第一关键字,以second为第二关键字比较大小。
nice!
如果要求返回值一定要按照frequency输出的话 还能用计数排序做吗?
可以的,计数排序可以将所有数排好序。
为啥呢?这里不是找到前n个的阈值然后扫一遍hashmap输出阈值之上的?为什么是有序的呢?
可以参考一下这篇文章 计数排序详解
(๑•̀ㅂ•́)و✧