LeetCodeHot100 347. 前 K 个高频元素

题目

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:

**输入:**nums = 1,1,1,2,2,3, k = 2

输出:1,2

示例 2:

**输入:**nums = 1, k = 1

输出:1

示例 3:

**输入:**nums = 1,2,1,2,1,2,3,1,3,2, k = 2

输出:1,2

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • k 的取值范围是 [1, 数组中不相同的元素的个数]
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

进阶: 你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n是数组大小。

思路解析

思路很简单,维护一个最小堆,这个堆大小为k,以元素的出现次数排序,达到k后看堆顶的元素次数进行对比然后判断是否移出去。

详细代码与注释

java 复制代码
class Solution {

    public int[] topKFrequent(int[] nums, int k) {

        /* =====================================================
         * 一、统计每个数字出现的次数
         * ===================================================== */

        // HashMap:key 是数字本身,value 是该数字出现的次数
        Map<Integer, Integer> count = new HashMap<>();

        // 遍历数组 nums
        for (int num : nums) {
            /*
             * count.getOrDefault(num, 0)
             * 如果 map 中已经存在 num,则返回 num 对应的次数
             * 如果 map 中不存在 num,则返回默认值 0
             */
            count.put(num, count.getOrDefault(num, 0) + 1);
        }

        /* =====================================================
         * 二、创建一个小顶堆(按出现次数排序)
         * ===================================================== */

        /*
         * PriorityQueue<int[]>:
         * 堆中存放的是 int 数组
         * 约定数组结构:
         *   arr[0] = 数字
         *   arr[1] = 该数字出现的次数
         */
        PriorityQueue<int[]> queue = new PriorityQueue<>(
            new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    /*
                     * 比较规则:按出现次数升序排序
                     * o1[1] - o2[1] < 0  → o1 优先
                     * 因此这是一个「小顶堆」
                     */
                    return o1[1] - o2[1];
                }
            }
        );

        /* =====================================================
         * 三、遍历 HashMap,把前 k 个高频元素放入堆中
         * ===================================================== */

        // 遍历 Map 中的每一对 (数字, 出现次数)
        for (Map.Entry<Integer, Integer> entry : count.entrySet()) {

            // 当前数字
            int num = entry.getKey();

            // 当前数字出现的次数
            int freq = entry.getValue();

            // 如果堆的大小已经等于 k,说明堆满了
            if (queue.size() == k) {

                /*
                 * peek() 查看堆顶元素(不删除)
                 * 由于是小顶堆,堆顶元素的出现次数是当前堆中最小的
                 */
                if (queue.peek()[1] < freq) {
                    // 当前数字出现次数更大,应该进入前 k

                    // 删除堆顶(出现次数最小的那个)
                    queue.poll();

                    // 把当前数字及其出现次数加入堆中
                    queue.offer(new int[]{num, freq});
                }

                // 如果当前频率 <= 堆顶频率
                // 说明排不进前 k,直接跳过

            } else {
                // 如果堆还没满 k 个元素,直接加入
                queue.offer(new int[]{num, freq});
            }
        }

        /* =====================================================
         * 四、从堆中取出结果
         * ===================================================== */

        // 结果数组,长度为 k
        int[] res = new int[k];

        // 依次从堆中取出元素
        for (int i = 0; i < k; i++) {
            /*
             * poll() 会取出并删除堆顶元素
             * 堆中存的是 [数字, 出现次数]
             * 我们只需要数字,所以取下标 0
             */
            res[i] = queue.poll()[0];
        }

        // 返回前 k 个高频元素
        return res;
    }
}
相关推荐
邓江洲1 小时前
一道经典的 NSString 内存面试题
面试
Escalating_xu1 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络
灯澜忆梦2 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下2 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
一个风轻云淡2 小时前
GCC 和 GDB命令简单解读
java·linux·前端
省钱兄--zs2 小时前
西安24小时自助健身房解决方案实战:系统开发与部署全流程指南
java·spring boot·系统架构·intellij-idea·需求分析
Evand J2 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛2 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
资料库012 小时前
Linux 8个常见运维故障排查
java·linux·运维