2025年- H65-Lc173--347.前k个高频元素(小根堆,堆顶元素是当前堆元素里面最小的)--Java版

1.题目描述

2.思路


(1)这里定义了一个小根堆(最小堆),根据元素的频率从小到大排序。小根堆原理:堆顶是最小值,每次插入或删除操作会保持堆的有序结构(常用二叉堆实现)。

比如,map.get(a) - map.get(b) 表示:

频率小的排在堆顶;

当堆满 k 个元素后,就可以比较新元素与堆顶的大小,进行替换。

(2)这个循环遍历 map 中的所有 key,目的是找出频率前 k 高的元素。

如果堆还没满,直接加入;

如果堆满了,比较当前元素的频率和堆顶元素频率:

当前元素更高,则替换堆顶。

继续例子(k = 2)

map: {1=3, 2=2, 3=1}

按顺序加入:

加入 1,堆 = [1]

加入 2,堆 = [1, 2](根据频率排序,2 的频率低,堆顶是 2)

处理 3(频率 1):

频率小于堆顶 2 → 不加入

最终堆中是 [1, 2]

🧩 举个例子来直观理解:

(1)输入:nums = [1, 1, 1, 2, 2, 3],k = 2

(2)频率统计结果:map = {1=3, 2=2, 3=1}

维护一个小根堆 pq,大小最多为 2(k=2):

加入 1(频率3)→ pq = [1]

加入 2(频率2)→ pq = [2, 1](按频率排序,堆顶是频率最小的)

尝试加入 3(频率1):

频率 1 < 堆顶 2 的频率 ⇒ 不加入

现在 pq 中是 [2, 1],是频率前 2 高的元素!

取出堆中元素:

int[] result = new int[k];

for (int i = 0; i < k; i++) {

result[i] = pq.remove(); // remove 堆顶元素

}

return result;

虽然 remove() 是按频率从小到大弹出,但我们关心的是内容是这 k 个元素本身是否是频率最高的

它不保证从大到小的顺序(如果你想要排好顺序,可以再排序)

总结这段逻辑:

小根堆始终维护的是「当前频率最高的前 k 个元素」;

取出这些元素即可完成任务;

堆顶是这 k 个元素中最小的,所以我们才用小根堆。

3.代码实现

java 复制代码
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        //使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
          HashMap<Integer, Integer> map = new HashMap<>();
          for (int num : nums) 
        {
            if(map.containsKey(num))
            {
                //如果字典元素在后续遍历的过程中又再次出现,直接次数+1
                 map.put(num, map.get(num) + 1);
            }else
            {
                //如果该字典元素是首次出现。
                map.put(num, 1);
            }
        }
        //遍历map,用最小堆保存频率最大的k个元素
        //优先级队列的底层原理就是堆
       PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
            public int compare(Integer a, Integer b) {
                return map.get(a) - map.get(b);  // 出现次数小的排前面(小根堆)
            }
        });
         // 遍历 map 的 key 值
        for (Integer key : map.keySet()) {
            if (pq.size() < k) {
                pq.add(key);  // 队列还未满,直接加入
            } else if (map.get(key) > map.get(pq.peek())) {
                pq.remove();      // 弹出堆顶元素(频率最小)
                pq.add(key);      // 加入当前频率更高的元素
            }
        }

        //取出最小堆的元素
       int[] result=new int[k];
       for(int i=0;i<k;i++)
       {
        result[i]=pq.remove();
       }
       return result;
       //pq.remove() 会返回堆顶元素,并从堆中删除该元素;
    }
}
相关推荐
缺点内向3 小时前
Java:创建、读取或更新 Excel 文档
java·excel
带刺的坐椅4 小时前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看5 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
应用市场5 小时前
构建自定义命令行工具 - 打造专属指令体
开发语言·windows·python
桦说编程5 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t5 小时前
ZIP工具类
java·zip
lang201509286 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
Dfreedom.6 小时前
一文掌握Python四大核心数据结构:变量、结构体、类与枚举
开发语言·数据结构·python·变量·数据类型
一半烟火以谋生6 小时前
Python + Pytest + Allure 自动化测试报告教程
开发语言·python·pytest
虚行6 小时前
C#上位机工程师技能清单文档
开发语言·c#