0
点赞
收藏
分享

微信扫一扫

LeetCode 347 前K个高频元素 -- 优先级队列

绪风 2022-01-30 阅读 55

题意:

给你一个整数数组 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 是数组大小。


参考文章

思路:

这道题其实就是考察优先级队列,而优先级队列其实就是大根堆或小根堆。

这道题的思路其实是不难的,也就是维护个小根堆,当堆的节点数量大于k时就把堆顶元素弹走就行,到最后保留在堆中的就是前k个高频元素。

不过在做这道题的时候我想起了之前学的一个知识点。之前在学习堆时,有一个关于如何获取一个数组中第k大数的操作,可以维护一个节点数为k的大根堆,到最后再弹出k-1次堆顶元素,最后剩下的元素就是第k大数。其实这个思路也是可以使用在这道题上,因为最后大根堆剩下的节点就是前k大的数。但是这个思路是需要我们自己动手实现的,没法用Java提供的PriorityQueue类来做,因为如果用PriorityQueue类的话当我们要维护数目k的大根堆时,我们每次只能得到大根堆中的堆顶也即最大的数,而没法得到大根堆中最小的数。

如果使用小根堆,那么在这道题中可以不手动实现大根堆,而是直接调用Java提供的PriorityQueue类。这道题做到最后反而感觉是考验对Java集合的使用熟练度,例如在PriorityQueue中使用比较器且注意比较器的写法,还有涉及到Map类的使用(如Entry类或getOrDefault方法)等,最好是可以自己重新写一遍,或者最少看一下代码中设计Java集合类的用法。

本题Java代码:

class Solution {
	public int[] topKFrequent(int[] nums, int k) {
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int num : nums) {
			map.put(num, map.getOrDefault(num, 0) + 1);
		}
		Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
		PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(
				(o1, o2) -> o1.getValue() - o2.getValue());
		for (Map.Entry<Integer, Integer> entry : entries) {
			queue.offer(entry);
			if (queue.size() > k)
				queue.poll();
		}
		int[] ans = new int[k];
		for (int i = k - 1; i >= 0; i--) {
			ans[i] = queue.poll().getKey();
		}
		return ans;
	}
}
举报

相关推荐

0 条评论