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() 会返回堆顶元素,并从堆中删除该元素;
    }
}
相关推荐
Python×CATIA工业智造16 分钟前
Frida RPC高级应用:动态模拟执行Android so文件实战指南
开发语言·python·pycharm
pianmian11 小时前
类(JavaBean类)和对象
java
我叫小白菜1 小时前
【Java_EE】单例模式、阻塞队列、线程池、定时器
java·开发语言
狐凄1 小时前
Python实例题:基于 Python 的简单聊天机器人
开发语言·python
Albert Edison2 小时前
【最新版】IntelliJ IDEA 2025 创建 SpringBoot 项目
java·spring boot·intellij-idea
超级小忍2 小时前
JVM 中的垃圾回收算法及垃圾回收器详解
java·jvm
weixin_446122462 小时前
JAVA内存区域划分
java·开发语言·redis
悦悦子a啊2 小时前
Python之--基本知识
开发语言·前端·python
勤奋的小王同学~3 小时前
(javaEE初阶)计算机是如何组成的:CPU基本工作流程 CPU介绍 CPU执行指令的流程 寄存器 程序 进程 进程控制块 线程 线程的执行
java·java-ee
TT哇3 小时前
JavaEE==网站开发
java·redis·java-ee