题目描述
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
提示:
1 <= nums.length <= 105
k
的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前
k
个高频元素的集合是唯一的
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n)
,其中 n
是数组大小。
解法
方法一:哈希表 + 优先队列(小根堆)
我们可以使用一个哈希表 $\textit{cnt}$ 统计每个元素出现的次数,然后使用一个小根堆(优先队列)来保存前 $k$ 个高频元素。
我们首先遍历一遍数组,统计每个元素出现的次数,然后遍历哈希表,将元素和出现次数存入小根堆中。如果小根堆的大小超过了 $k$,我们就将堆顶元素弹出,保证堆的大小始终为 $k$。
最后,我们将小根堆中的元素依次弹出,放入结果数组中即可。
时间复杂度 $O(n \times \log k)$,空间复杂度 $O(k)$。其中 $n$ 是数组的长度。
| class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
cnt = Counter(nums)
return [x for x, _ in cnt.most_common(k)]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> cnt = new HashMap<>();
for (int x : nums) {
cnt.merge(x, 1, Integer::sum);
}
PriorityQueue<Map.Entry<Integer, Integer>> pq
= new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));
for (var e : cnt.entrySet()) {
pq.offer(e);
if (pq.size() > k) {
pq.poll();
}
}
return pq.stream().mapToInt(Map.Entry::getKey).toArray();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> cnt;
using pii = pair<int, int>;
for (int x : nums) {
++cnt[x];
}
priority_queue<pii, vector<pii>, greater<pii>> pq;
for (auto& [x, c] : cnt) {
pq.push({c, x});
if (pq.size() > k) {
pq.pop();
}
}
vector<int> ans;
while (!pq.empty()) {
ans.push_back(pq.top().second);
pq.pop();
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | func topKFrequent(nums []int, k int) []int {
cnt := map[int]int{}
for _, x := range nums {
cnt[x]++
}
pq := hp{}
for x, c := range cnt {
heap.Push(&pq, pair{x, c})
if pq.Len() > k {
heap.Pop(&pq)
}
}
ans := make([]int, k)
for i := 0; i < k; i++ {
ans[i] = heap.Pop(&pq).(pair).v
}
return ans
}
type pair struct{ v, cnt int }
type hp []pair
func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool { return h[i].cnt < h[j].cnt }
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | function topKFrequent(nums: number[], k: number): number[] {
const cnt = new Map<number, number>();
for (const x of nums) {
cnt.set(x, (cnt.get(x) ?? 0) + 1);
}
const pq = new MinPriorityQueue();
for (const [x, c] of cnt) {
pq.enqueue(x, c);
if (pq.size() > k) {
pq.dequeue();
}
}
return pq.toArray().map(x => x.element);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | use std::cmp::Reverse;
use std::collections::{BinaryHeap, HashMap};
impl Solution {
pub fn top_k_frequent(nums: Vec<i32>, k: i32) -> Vec<i32> {
let mut cnt = HashMap::new();
for x in nums {
*cnt.entry(x).or_insert(0) += 1;
}
let mut pq = BinaryHeap::with_capacity(k as usize);
for (&x, &c) in cnt.iter() {
pq.push(Reverse((c, x)));
if pq.len() > k as usize {
pq.pop();
}
}
pq.into_iter().map(|Reverse((_, x))| x).collect()
}
}
|