给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
进阶:你所设计算法的时间复杂度 必须 优于 O(nlogn) ,其中 n 是数组大小。
3种方法:部分快排思想;直接排序;优先队列
方法1:最小堆
作者:cxywushixiong
链接:https://leetcode-cn.com/problems/top-k-frequent-elements/solution/leetcode-di-347-hao-wen-ti-qian-k-ge-gao-pin-yuan-/
时间复杂度:O(nlogk),n 表示数组的长度。首先,遍历一遍数组统计元素的频率,这一系列操作的时间复杂度是O(n);接着,遍历用于存储元素频率的 map,如果元素的频率大于最小堆中顶部的元素,则将顶部的元素删除并将该元素加入堆中,这里维护堆的数目是 k,所以这一系列操作的时间复杂度是 O(nlogk) 的;因此,总的时间复杂度是 O(nlogk)。
空间复杂度:O(n),最坏情况下(每个元素都不同),map 需要存储 n 个键值对,优先队列需要存储 k 个元素,因此,空间复杂度是 O(n)。
方法2:桶排序
设置若干个桶,每个桶存储出现频率相同的数。桶的下标表示数出现的频率,即第 i 个桶中存储的数出现的频率为 i。
把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。
首先依旧使用哈希表统计频率,统计完成后,创建一个数组,将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标即可。
时间复杂度:O(n),n 表示数组的长度。首先,遍历一遍数组统计元素的频率,这一系列操作的时间复杂度是 O(n);桶的数量为 n+1,所以桶排序的时间复杂度为 O(n);因此,总的时间复杂度是 O(n)。
空间复杂度:很明显为 O(n)。
方法3:python的Counter()
统计每个数的频率,输出最大的几个,这完全迎合了Python中的Counter类,调用其的几个方法即可。
Counter 是一个在collections包里的类,正如其名,是一个用于计数的工具。
我们可以用Counter(nums)这样的构造函数构造一个Counter类,其中nums是一个列表。
构造好的Counter实例可以看作一个字典,键是nums的每一项,值是它的出现次数。
如果上面的叙述让你感到很混乱的话,我不妨举个例子。
如果一个列表a = [1,1,3,4,3],你想要统计每项的出现次数,那么你使用b = Counter(a),那么这时候b就像一个这样的字典{1:2,3:2,4:1},表示数字1出现了2次,数字3出现了2次,数字4出现了1次。
可是题目里要我们输出的是最多的K项,这时候可以应用Counter的一个函数,most_common(k),这个函数就是返回最多出现的K项
但是返回的形式是一个元祖列表,类似[(1,2),(3,2),(4,1)]的形式,我们只需要键也就是第一项,所以要使用列表生成式处理一下即可。
class Solution: def topKFrequent(self, nums: List[int], k: int) -> List[int]: from collections import Counter return [i[0] for i in Counter(nums).most_common(k)] 作者:qsctech-sange 链接:https://leetcode-cn.com/problems/top-k-frequent-elements/solution/yi-xing-python3dai-ni-zou-jin-counterlei-by-jimmy0/