应知应会 - 堆与优先队列
概述
堆是一种完全二叉树,用数组底层存储;分为:
- 大根堆:根节点值 ≥ 左右孩子,堆顶是最大值
- 小根堆:根节点值 ≤ 左右孩子,堆顶是最小值、
优先队列(PriorityQueue):
Java 里 PriorityQueue 本质就是小根堆;
优先队列 = 对外的逻辑结构,堆 = 底层实现结构。
核心特性:每次只能从队首取出优先级最高 / 最小 / 最大的元素。
优先队列 = 对外的逻辑结构,堆 = 底层实现结构。
核心特性:每次只能从队首取出优先级最高 / 最小 / 最大的元素。
详解
- 堆是完全二叉树,可用数组顺序存储,不需要链表
- 满足堆序性质:
- 小根堆:父节点 ≤ 子节点,堆顶永远最小
- 大根堆:父节点 ≥ 子节点,堆顶永远最大
- 核心操作复杂度:
- 插入、删除堆顶:O(logn)
- 遍历找最值:比普通数组 O(n) 快很多
适用场景
- 频繁求最大值 / 最小值
- TopK 问题:前 K 大、前 K 小
- 多路归并、有序合并
- 贪心算法配套:每次选当前最优
- 任务调度、哈夫曼编码
- 滑动窗口最大值
常用解题思路
TopK 经典思路
求前 K 大 → 用小根堆,保持堆大小为 K,遍历完堆里就是最大 K 个
求前 K 小 → 用大根堆
每次取最值贪心
每次弹出堆顶最优值,处理后把新元素再入堆
双堆用法
一个大根堆存左半边小数,一个小根堆存右半边大数 → 求数据流中位数
常见考题
数组第k大元素
题目:给一个整数数组 nums 和整数 k,求数组中第k个最大元素。
注意:是排序后从大到小第 K 个,不是第 K 小。
分析:维护PriorityQueue,小根堆,堆顶元素是最小的。如果堆的size < k,则元素入堆。否则,检查元素和当前堆顶谁大,大的留在堆中。遍历结束后,堆顶就是第 K 大。
public static int solve(int[] nums, int k) { // 默认小根堆 PriorityQueue<Integer> heap = new PriorityQueue<>(); for (int num : nums) { if (heap.size() < k) { heap.offer(num); } else if (num > heap.peek()) { heap.poll(); heap.offer(num); } } return heap.peek(); }
Top K 个高频元素
题目:给定数组,统计每个元素出现频率,返回出现频率最高的 k 个元素。
分析:用HashMap统计出现次数,用小根堆,只存 k 个元素,每次淘汰到最小的。最后堆中剩的就是。

浙公网安备 33010602011771号