一、题目解析:查找热点数据问题
问题描述
给你一个整数数组 nums 和一个整数 k,请你用一个字符串返回其中出现频率前 k 高的元素。请按升序排列。
你所设计算法的时间复杂度必须优于 O(n log n),其中 n 是数组大小。
输入
- nums: 一个正整数数组
- k: 一个整数
返回
返回一个包含 k 个元素的字符串,数字元素之间用逗号分隔。数字元素按升序排列,表示出现频率最高的 k 个元素。
参数限制
- 1 <= nums[i] <= 10^4
- 1 <= nums.length <= 10^5
- k 的取值范围是 [1, 数组中不相同的元素的个数]
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的
题目思路
-
题目分析:这道题用Map及其相关的方法即可解答:
- 建立Map<Integer, Integer>,建立数据和出现个数的对应关系
- 对Map进行降序排序
- 按照题目要求输出指定数据
基于以上思路,我们需要了解Map的创建,元素的添加,排序等操作
-
Java中的Map操作
- 建立:
Map<Integer, Integer> frequencyMap = new HashMap<>();确定键值对的类型(不能为基本数据类型),使用new关键字创建对象 - 添加元素:使用
getOrDefault方法判断Map中有无该元素,若有则返回该元素的值,若无则为0,再使用put方法设置该键的值 - 排序:使用优先队列
PriorityQueue来找到频率最高的前 k 个元素(排序,从大到小) - 取元素:用
Map.Entry遍历Map
有了以上操作,我们就可以完成这道题啦
- 建立:
代码实现
Java 代码:
public static String solution(int[] nums, int k) {
// 统计每个元素的频率
Map<Integer, Integer> frequencyMap = new HashMap<>();
for (int num : nums) {
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
}
// 使用优先队列(最小堆)来找到频率最高的前 k 个元素(排序,从大到小)
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>(
(a, b) -> -a.getValue() + b.getValue()
);
// 取元素
for (Map.Entry<Integer, Integer> entry : frequencyMap.entrySet()) {
minHeap.offer(entry);
if (minHeap.size() >= k) {
break;
}
}
// 转为字符串
StringBuilder result = new StringBuilder();
for (int i = 0; i < k; i++) {
result.append(minHeap.poll().getKey());
if (i < k - 1) {
result.append(",");
}
}
return result.toString();
}
代码详解
- 初始化:建立空的Map
frequencyMap = new HashMap<>()。 - 遍历操作:利用
for循环将数组中的每个元素累计到frequencyMap中 - 时间复杂度分析:使用了一个
PriorityQueue(最小堆)来找到频率最高的前 k 个元素。插入和删除操作的时间复杂度是 O(log k)。 - 空间复杂度分析:
HashMap的空间复杂度是 O(m),其中 m 是数组。PriorityQueue的空间复杂度是 O(k)。总空间复杂度O(k+m)
二、知识总结:优先队列和哈希表的应用
在解题过程中,我加深了对“优先队列”和“哈希表”这两种数据结构的理解:
-
优先队列(PriorityQueue) :
- 特性:优先队列是一种基于堆的数据结构,能够高效地获取和删除最小(或最大)元素。在本题中,我们使用优先队列来维护频率最高的前 k 个元素。
- 实际应用:优先队列常用于需要频繁获取最大或最小值的场景,如任务调度、数据流中的中位数查找等。
-
哈希表(HashMap) :
- 特性:哈希表是一种高效的数据结构,能够在平均 O(1) 时间内进行插入、删除和查找操作。在本题中,我们使用哈希表来统计每个元素的频率。
- 实际应用:哈希表广泛应用于需要快速查找和存储键值对的场景,如缓存系统、字典实现等。
学习建议
对于初学者,可以通过以下方法巩固对优先队列和哈希表的理解:
- 多练习类似的题目:尝试解决更多涉及优先队列和哈希表的问题,如“Top K 频繁元素”、“最长连续序列”等。
- 理解并手动推导:手动推导数据结构的操作过程,直观感受其工作原理和性能特点。
- 阅读相关文档和教程:深入学习 Java 中
PriorityQueue和HashMap的实现细节和使用方法。
通过这些方法,可以更好地掌握优先队列和哈希表的应用,提升算法设计和实现的能力。