问题描述
给你一个整数数组 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 个高频元素的集合是唯一的
测试样例
样例1:
输入:
nums = [1, 1, 1, 2, 2, 3], k = 2
输出:"1,2"
解释:元素 1 出现了 3 次,元素 2 出现了 2 次,元素 3 出现了 1 次。因此前两个高频元素是 1 和 2。
样例2:
输入:
nums = [1], k = 1
输出:"1"
样例3:
输入:
nums = [4, 4, 4, 2, 2, 2, 3, 3, 1], k = 2
输出:"2,4"
思路
- 统计每个元素的频率:我们可以使用一个
HashMap来存储每个元素及其出现的次数。 - 根据频率排序:我们需要根据元素的频率进行排序。由于题目要求时间复杂度优于
O(n log n),我们可以使用一个大小为k的最小堆(优先队列)来维护频率最高的k个元素。 - 构建结果字符串:最后,我们将频率最高的
k个元素按升序排列,并构建结果字符串。
这题我用Java来实现。getOrDefault用法 getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。
getOrDefault() 方法的语法为:
hashmap.getOrDefault(Object key, V defaultValue)
注: hashmap 是 HashMap 类的一个对象。
参数说明:
- key - 键
- defaultValue - 当指定的key并不存在映射关系中,则返回的该默认值
返回值
返回 key 相映射的的 value,如果给定的 key 在映射关系中找不到,则返回指定的默认值。
Java中的Map操作
-
建立:
Map<Integer, Integer> frequencyMap = new HashMap<>();确定键值对的类型(不能为基本数据类型),使用new关键字创建对象 -
添加元素:使用
getOrDefault方法判断Map中有无该元素,若有则返回该元素的值,若无则为0,再使用put方法设置该键的值 -
排序:使用优先队列
PriorityQueue来找到频率最高的前 k 个元素(排序,从大到小) -
取元素:用
Map.Entry遍历Map
学习建议
对于初学者,可以通过以下方法巩固对优先队列和哈希表的理解:
- 多练习类似的题目:尝试解决更多涉及优先队列和哈希表的问题,如“Top K 频繁元素”、“最长连续序列”等。
- 理解并手动推导:手动推导数据结构的操作过程,直观感受其工作原理和性能特点。
- 阅读相关文档和教程:深入学习 Java 中
PriorityQueue和HashMap的实现细节和使用方法。
通过这些方法,可以更好地掌握优先队列和哈希表的应用,提升算法设计和实现的能力。
代码实现
public class Main {
public static String solution(int[] nums, int k) {
// Step 1: 统计每个元素的频率
Map<Integer, Integer> frequencyMap = new HashMap<>();
for (int num : nums) {
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
}
// Step 2: 使用最小堆来维护频率最高的 k 个元素
PriorityQueue<Integer> minHeap = new PriorityQueue<>(
(a, b) -> frequencyMap.get(a) - frequencyMap.get(b)
);
for (int num : frequencyMap.keySet()) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll(); // 保持堆的大小为 k
}
}
// Step 3: 构建结果字符串
List<Integer> resultList = new ArrayList<>(minHeap);
Collections.sort(resultList); // 按升序排列
StringBuilder result = new StringBuilder();
for (int i = 0; i < resultList.size(); i++) {
if (i > 0) {
result.append(",");
}
result.append(resultList.get(i));
}
return result.toString();
}
public static void main(String[] args) {
int[] nums1 = {1, 1, 1, 2, 2, 3};
int[] nums2 = {1};
System.out.println(solution(nums1, 2).equals("1,2"));
System.out.println(solution(nums2, 1).equals("1"));
}
}
``