1. 题目
https://leetcode.cn/problems/top-k-frequent-elements/
考察点
这道题的考察点是:
- 如何使用哈希表来统计元素的出现频率。
- 如何使用最小堆来找出前k个高频元素。
- 如何利用堆的性质来优化时间复杂度。
- 如何使用合适的数据结构来存储和返回结果。
2. 解法
思路
Leetcode 347题,这是一个关于找出数组中出现频率最高的k个元素的问题。
有多种方法可以实现这个问题,但是题目要求算法的时间复杂度必须优于O(n log n),其中n是数组的大小。
一种可能的方法是使用哈希表和最小堆。
- 哈希表可以用来存储每个元素出现的次数,
- 然后遍历哈希表,将元素和次数作为一个对放入最小堆中,
- 如果堆的大小超过k,就弹出堆顶元素,这样保证堆中只有出现次数最高的k个元素。
- 最后,将堆中的元素放入一个列表中返回。
这种方法的时间复杂度是O(n log k),空间复杂度是O(n)。
代码逻辑
- 用哈希表记录每个元素的出现次数。
- 我们创建一个哈希表map,用来存储数组中每个元素出现的次数。我们遍历数组中的每个元素num,如果map中已经有num作为键,就将其对应的值加一,否则就将num作为键,1作为值放入map中。这样,map中就记录了数组中每个元素及其出现的次数。
- 用最小堆维护出现次数最高的k个元素。
- 我们创建一个最小堆queue,用来存储元素和次数的对。我们遍历map中的每个键值对entry,将entry的键和值作为一个数组放入queue中。如果queue的大小超过了k,就说明queue中有不属于前k个高频元素的元素,我们就将queue的堆顶元素弹出。这样,queue中就保留了出现次数最高的k个元素及其次数。
- 用列表存储最小堆中的元素。
- 我们创建一个列表list,用来存储最终的结果。我们将queue中的每个元素弹出,并将其第一个元素(即原数组中的元素)放入list中。这样,list中就包含了前k个高频元素。
- 用数组返回列表中的元素。
- 我们创建一个数组res,用来返回结果。我们遍历list中的每个元素,并将其放入res中。这样,res就是一个包含前k个高频元素的数组。
以上就是代码的逻辑概述。
具体实现
import java.util.*; class Solution { public int[] topKFrequent(int[] nums, int k) { // 哈希表存储元素和次数 Map<Integer, Integer> map = new HashMap<>(); for (int num : nums) { map.put(num, map.getOrDefault(num, 0) + 1); } // 最小堆存储元素和次数的对 PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[1] - b[1]); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { queue.offer(new int[]{entry.getKey(), entry.getValue()}); if (queue.size() > k) { queue.poll(); } } // 将堆中的元素放入列表中 List<Integer> list = new ArrayList<>(); while (!queue.isEmpty()) { list.add(queue.poll()[0]); } // 将列表转换为数组并返回 int[] res = new int[k]; for (int i = 0; i < k; i++) { res[i] = list.get(i); } return res; } }