查找热点数据问题-青训营X豆包MarsCode 技术训练营刷题分享 | 豆包MarsCode AI 刷题

145 阅读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. 题目分析:这道题用Map及其相关的方法即可解答:

    • 建立Map<Integer, Integer>,建立数据和出现个数的对应关系
    • 对Map进行降序排序
    • 按照题目要求输出指定数据

    基于以上思路,我们需要了解Map的创建,元素的添加,排序等操作

  2. 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();
    }

代码详解

  • 初始化:建立空的MapfrequencyMap = new HashMap<>()
  • 遍历操作:利用 for 循环将数组中的每个元素累计到frequencyMap
  • 时间复杂度分析:使用了一个 PriorityQueue(最小堆)来找到频率最高的前 k 个元素。插入和删除操作的时间复杂度是 O(log k)。
  • 空间复杂度分析HashMap 的空间复杂度是 O(m),其中 m 是数组。PriorityQueue 的空间复杂度是 O(k)。总空间复杂度O(k+m)

二、知识总结:优先队列和哈希表的应用

在解题过程中,我加深了对“优先队列”和“哈希表”这两种数据结构的理解:

  1. 优先队列(PriorityQueue)

    • 特性:优先队列是一种基于堆的数据结构,能够高效地获取和删除最小(或最大)元素。在本题中,我们使用优先队列来维护频率最高的前 k 个元素。
    • 实际应用:优先队列常用于需要频繁获取最大或最小值的场景,如任务调度、数据流中的中位数查找等。
  2. 哈希表(HashMap)

    • 特性:哈希表是一种高效的数据结构,能够在平均 O(1) 时间内进行插入、删除和查找操作。在本题中,我们使用哈希表来统计每个元素的频率。
    • 实际应用:哈希表广泛应用于需要快速查找和存储键值对的场景,如缓存系统、字典实现等。

学习建议
对于初学者,可以通过以下方法巩固对优先队列和哈希表的理解:

  1. 多练习类似的题目:尝试解决更多涉及优先队列和哈希表的问题,如“Top K 频繁元素”、“最长连续序列”等。
  2. 理解并手动推导:手动推导数据结构的操作过程,直观感受其工作原理和性能特点。
  3. 阅读相关文档和教程:深入学习 Java 中 PriorityQueue 和 HashMap 的实现细节和使用方法。

通过这些方法,可以更好地掌握优先队列和哈希表的应用,提升算法设计和实现的能力。