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() 会返回堆顶元素,并从堆中删除该元素;
    }
}
相关推荐
海棠蚀omo2 分钟前
C++笔记-C++11(一)
开发语言·c++·笔记
紫乾20142 分钟前
idea json生成实体类
java·json·intellij-idea
wh_xia_jun8 分钟前
在 Spring Boot 中使用 JSP
java·前端·spring boot
网安INF9 分钟前
CVE-2020-17518源码分析与漏洞复现(Flink 路径遍历)
java·web安全·网络安全·flink·漏洞
Y第五个季节13 分钟前
docker-部署Nginx以及Tomcat
java·开发语言
IT-ZXT88817 分钟前
Tomcat 线程模型详解&性能调优
java·tomcat
小道士写程序34 分钟前
Qt 5.12 上读取 .xlsx 文件(Windows 平台)
开发语言·windows·qt
ou.cs1 小时前
c# :this() 和 :base()区别
开发语言·c#
Mikhail_G1 小时前
Python应用函数调用(二)
大数据·运维·开发语言·python·数据分析
lanfufu1 小时前
记一次诡异的线上异常赋值排查:代码没错,结果不对
java·jvm·后端