Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目:给定一个整数数组和一个整数k,要求返回在数组中出现频率前k高的元素。要求算法的时间复杂度必须优于。
解题思路
本题可拆解为:
- 统计各个元素的频率。
- 输出前
k个频率较高的元素。
统计元素的频率很简单,我们可以使用HashMap来进行统计,难点在于统计完之后如何输出前K个频率较高的元素。
这里我的思路是使用一个集合将这些元素装入,因为Java中集合有List.sort()方法,我们可以调用该方法定义排序规则即可,最后输出前k个元素到一个数组中即可得到最终答案,代码如下:
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(!map.containsKey(nums[i])){
map.put(nums[i], 0);
}
map.put(nums[i], map.get(nums[i])+1);
}
List<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
list.sort((o1, o2) -> o2.getValue() - o1.getValue());
int[] result = new int[k];
for(int i=0;i<k;i++){
result[i] = list.get(i).getKey();
}
return result;
}
时间复杂度为,主要在于集合排序的时间复杂度,空间复杂度为。
上述方法是较为简单的,看了题解之后发现有人使用优先级队列来进行前K个元素的获取,在使用优先级队列的时候需要将map进行拆解到一个数组中,之后使用这个数组重写比较器方法,后面的操作都类似,个人感觉没有上面的好理解,代码如下:
public int[] topKFrequent2(int[] nums, int k) {
Map<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
// int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
PriorityQueue<int[]> queue = new PriorityQueue<int[]>((m, n) -> m[1] - n[1]);
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
int num = entry.getKey(), count = entry.getValue();
if (queue.size() == k) {
if (queue.peek()[1] < count) {
queue.poll();
queue.offer(new int[]{num, count});
}
} else {
queue.offer(new int[]{num, count});
}
}
int[] ret = new int[k];
for (int i = 0; i < k; ++i) {
ret[i] = queue.poll()[0];
}
return ret;
}
时间复杂度和空间复杂度和上面一样。