题目描述
给定一个非空整数数组,请返回出现次数最多的 $k$ 个数。
注意:
- 你可以假定 $k$ 一定是合法的,即 $1 \le k \le$ 数组中不同元素的个数,且排名在第 $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;
}
};
前面统计每个元素出现次数可以理解,到 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输出阈值之上的?为什么是有序的呢?
可以参考一下这篇文章 计数排序详解
(๑•̀ㅂ•́)و✧