ZaynPei Lv6

当你需要在一个动态的集合中(元素不断在增加或减少)快速地查找并(或)移除“最值”(最大值或最小值)时,堆就是你的不二之选。

Top-K 问题 / 第 K 小/大

这是堆最基础、最直接的应用。核心思想是:维护一个大小固定为 K 的堆。这个堆里存储了你到目前为止见过的 “Top K” 个元素。

问题模型: - 静态数组:在 N 个元素中找到第 K 大的元素 (LC 215)。 - 数据流:在不断加入的数据流中,始终保持对第 K 大元素的快速访问 (LC 703)。

解题思路 (以“第 K 大”为例):你需要一个最小堆(Min-Heap)。为什么? 最小堆的堆顶 min_pq.top() 永远是堆中最小的元素。如果我们的堆里有 K 个元素,那么堆顶就是K 个元素中的第 K的那个。 - 初始化:创建一个大小为 K 的最小堆 min_pq。 - 遍历数据:for (int num : nums) - 入堆:min_pq.push(num); - 维护大小:if (min_pq.size() > k):min_pq.pop(); - (将堆中最小的元素——即“第 K+1 大”的元素——扔掉) - 获取答案:当所有数据都处理完毕后,堆中剩下的 K 个元素就是最大的 K 个,而 min_pq.top() 就是我们想要的第 K 大元素。

对顶堆(动态中位数)

一个极其精妙的技巧, 使用两个堆来将一个动态数据流“从中间劈开”,从而 O(1) 访问中位数。

数据结构配置: - small (最大堆):存储数据流中较小的一半元素。small.top() 是“小半”中的最大值。 - large (最小堆):存储数据流中较大的一半元素。large.top() 是“大半”中的最小值。

核心规则(不变式): - small.size() 永远等于 large.size()(当总数为偶) - 或 small.size() 等于 large.size() + 1(当总数为奇)中位数:如果总数为奇,

中位数就是 small.top()。如果总数为偶,中位数就是 (small.top() + large.top()) / 2。

重排元素(贪心)

反悔堆(反悔贪心)