0%

Leetcode 347 Top K Frequent Elements

Given a non-empty array of integers, return the k\ most frequent elements.

Example 1:

1
2
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:

1
2
Input: nums = [1], k = 1
Output: [1]

Note:

  • You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  • Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
  • It’s guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
  • You can return the answer in any order.

1. 暴力

使用一个hashmap存储每个数字出现的次数, 按次数排序, 取前k个.

时间复杂度为O(max(n, m*logm)) 其中n为数组长度, m为数组中不同元素的总个数

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
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int i : nums)
{
map.putIfAbsent(i,0);
map.put(i, map.get(i) + 1);
}
Map.Entry<Integer, Integer>[] arr = (Map.Entry<Integer, Integer>[]) new Map.Entry[map.size()];
int s = 0;
for(Map.Entry<Integer, Integer> entry : map.entrySet())
{
arr[s++] = entry;
}
Arrays.sort(arr, (entry1, entry2) -> {
return entry2.getValue() - entry1.getValue();
});
int[] ans = new int[k];
for(int i = 0; i < k; ++i)
{
ans[i] = arr[i].getKey();
}
return ans;
}
}

2. 优先队列

和1的思路差不多, 都要先用hashmap. 但是之后可以用优先队列完成选取前k个的操作. 时间复杂度可降为O(max(n, m*logk)) 其中n为数组长度, m为数组中不同元素的总个数.

这里还想到了用快速排序的partition思想求的第k大的数, 可以将复杂度降为O(n). 但是这是行不通的. 因为需要求全部的第1大, 第2大, … 第k大. 而不是仅仅求出第k大的数就可以的.

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
28
29
30
31
32
33
34
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int i : nums)
{
map.putIfAbsent(i,0);
map.put(i, map.get(i) + 1);
}
PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>((entry1, entry2) -> entry1.getValue() - entry2.getValue());
for(Map.Entry<Integer, Integer> entry : map.entrySet())
{
if(pq.size() < k)
{
pq.offer(entry);
}
else
{
Map.Entry<Integer, Integer> top = pq.peek();
if(top.getValue() < entry.getValue())
{
pq.poll();
pq.offer(entry);
}
}
}
int[] ans = new int[k];
int s = 0;
for(Map.Entry<Integer, Integer> entry : pq)
{
ans[s++] = entry.getKey();
}
return ans;
}
}

3.桶排序

因为待排序的值都在0到n这个范围内, 所以可以用桶排序. 复杂度O(n)

这也提醒了我们当排序的范围不大的时候, 可以用这种非比较排序算法.

平常基本上不用桶排序, 所以很难想到这个方法. 所以还是要多练习, 多总结.

再选取前k个即可.

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
28
29
30
31
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for(int i : nums)
{
map.put(i, map.getOrDefault(i, 0) + 1);
}
List<Integer>[] bucket = (List<Integer>[]) new List[nums.length + 1];
for(int i = 0; i != bucket.length; ++i)
{
bucket[i] = new ArrayList<Integer>();
}
for(Map.Entry<Integer, Integer> entry : map.entrySet())
{
bucket[entry.getValue()].add(entry.getKey());
}
int[] ans = new int[k];
int s = 0;
for(int i = bucket.length - 1; i != -1; --i)
{
for(int j : bucket[i])
{
if(s == k)
break;
ans[s++] = j;
}
}
return ans;

}
}