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() 会返回堆顶元素,并从堆中删除该元素;
    }
}
相关推荐
特立独行的猫a19 分钟前
C 语言各种指针详解
java·c语言·开发语言
Rewloc1 小时前
Trae CN配置Maven环境
java·maven
彭于晏Yan1 小时前
MyBatis-Plus使用动态表名分表查询
java·开发语言·mybatis
秋月的私语3 小时前
如何快速将当前的c#工程发布成单文件
android·java·c#
天***88963 小时前
使用python写一个应用程序要求实现微软常用vc++功能排查与安装功能
java
代码充电宝4 小时前
LeetCode 算法题【简单】283. 移动零
java·算法·leetcode·职场和发展
MediaTea6 小时前
Python IDE:Spyder
开发语言·ide·python
不枯石7 小时前
Matlab通过GUI实现点云的均值滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab·均值算法
不枯石7 小时前
Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
ccccczy_7 小时前
Spring Security 深度解读:JWT 无状态认证与权限控制实现细节
java·spring security·jwt·authentication·authorization·securityfilterchain·onceperrequestfilter