查找热点数据问题| 豆包MarsCode AI刷题

133 阅读4分钟

查找热点数据问题

问题描述

给你一个整数数组 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高的元素。

思路:

  1. 计算频次
    • 计算数组每个元素的出现频率。可用HashMap来记录每个元素及其对应的频率。
  2. 对频次进行排序
    • 对频率进行排序。题目要求时间复杂度优于 O(n log n)
  3. 取出前k个元素
  4. 拼接结果

代码解析

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帮忙查找问题,以及调理分析,更便于查找出问题所在,帮助很大~

89822D38AB234E4A2EC1836C3E79B89E.png