查找热点数据问题
问题描述
给你一个整数数组 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:
输入:
nmums = [1,1,1,2,2,3],k =2输出:"1,2"解释:元素1出现了3次,元素2出现了2次,元素3出现了1次。因此前两个高频元素是1和2
样例2:
输入:
nums = [1],k =1输出:"1"
本题目标:要求返回频率前k高的元素。
思路:
- 计算频次
- 计算数组每个元素的出现频率。可用HashMap来记录每个元素及其对应的频率。
- 对频次进行排序
- 对频率进行排序。题目要求时间复杂度优于 O(n log n)
- 取出前k个元素
- 拼接结果
代码解析
1. 使用 HashMap 记录频次
Map<Integer,Integer> frequencyMap = new HashMap<>();
for(int num: nums){
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0)+1);
}
以上这一步,也可以写成
Map<Integer, Integer> frequencyMap = new HashMap<>();
for (int num : nums) {
if (frequencyMap.containsKey(num)) {
// 如果数字已经在 Map 中,增加其出现次数
frequencyMap.put(num, frequencyMap.get(num) + 1);
} else {
// 如果数字不在 Map 中,将其添加并初始化为 1
frequencyMap.put(num, 1);
}
}
对应知识点分析
HashMap是键值对存储的数据结构,可以快速查找和插入数据。-----> (在本题中,我们使用HashMap来记录每个元素出现的频率。)getOrDefault是Java中的 Map 接口提供的一个方法,用于从 Map 中获取指定键的值,如果该键不存在,则返回一个默认值。----> (1. 可以避免在获得值时出现 null 的情况,非常适合统计频率、计数等场景使用。2. 用法:第一个参数:要获取值的键;第二个参数:若键不存在时 返回的默认值)
2. 对频次进行排序
// sortedEntries 存储频次排序
List<Map.Entry<Integer, Integer>> sortedEntries = new ArrayList<>(frequencyMap.entrySet());
sortedEntries.sort((a, b) -> b.getValue().compareTo(a.getValue()));
对应知识点分析
Map.Entry是HashMap中的一个内部接口,表示键值对。List是一种有序的集合,可以存储多个元素,并且允许重复。 ----> 在本题中,我们使用List来存储排序后的频率和最终的结果。
3. 取出前k个元素
// 取出前 k 个元素并按升序排列
List<Integer> topK = new ArrayList<>();
for (int i = 0; i < k; i++) {
// 将 sortedEntries 列表中索引为 i 的元素的键(即元素本身)添加到toK列表中。
topK.add(sortedEntries.get(i).getKey());
}
Collections.sort(topK);
对应知识点分析
List.get(i)表示获得 List 列表中索引为 i 的元素,这个元素是一个Map.Entry,表示一个键值对。--->(本题中的 sortedEntries.get(i),sortedEntries是一个List,存储了frequencyMap中的所有键值对(即元素及其频率),并且这些键值对已经按照频率从高到低排序。)List.get(i).getKey()表示获取List 列表中索引为 i 的元素的键(即元素本身)Collecttions.sort是Java提供的一个排序方法,可以对List中的元素进行排序。---> 本题中,我们使用它来对频率进行排序。
4. 拼接结果
// 拼接结果
StringBuilder result = new StringBuilder();
for (int i = 0; i < topK.size(); i++) {
if (result.length() > 0) {
result.append(",");
}
result.append(topK.get(i));
}
return result.toString();
对应知识点分析
StringBuilder是一种可变的字符串类,用于高效地拼接字符串。
完整代码:
import java.util.*;
public class Main {
public static String solution(int[] nums, int k) {
// 判断nums数组中,输出 出现频率大于k的数字。
// 要求:算法时间复杂度O(n·log n),升序排列
// frequencyMap 记录每个元素的频率
Map<Integer, Integer> frequencyMap = new HashMap<>();
for(int num: nums){
// 若数字已存在,则频次加一;若不存在Map中,将其添加并初始化为1
frequencyMap.put(num, frequencyMap.getOrDefault(num, 0)+1);
}
// 对频率进行排序
List<Map.Entry<Integer, Integer>> sortedEntries = new ArrayList<>(frequencyMap.entrySet());
sortedEntries.sort((a,b) -> b.getValue().compareTo(a.getValue()));
// 取出前 k 个元素并按升序排列
List<Integer> topK = new ArrayList<>();
for (int i = 0; i < k; i++) {
topK.add(sortedEntries.get(i).getKey());
}
Collections.sort(topK);
// 拼接结果
StringBuilder result = new StringBuilder();
for (int i = 0; i < topK.size(); i++) {
if (result.length() > 0) {
result.append(",");
}
result.append(topK.get(i));
}
return result.toString();
}
public static void main(String[] args) {
// You can add more test cases here
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"));
}
}
感受
不知不觉,青训营的时光快要过半了,时间过得好快呀。本次呢,通过豆包ai帮忙查找问题,以及调理分析,更便于查找出问题所在,帮助很大~