面试Leetcode - Heap 堆

Heap

堆 = 一个能快速拿到"当前最小值/最大值"的特殊数据结构。

核心价值是动态维护一个集合中的最大/最小元素。

最常见的是两种:

  • Min Heap(小根堆):堆顶永远是最小值
  • Max Heap(大根堆):堆顶永远是最大值

比如:

复制代码
       1
      / \
     3   5
    / \
   7   8

这是一个小根堆,因为:

1 < 3, 5

3 < 7, 8

但是注意:堆不是完全排序的。

比如 [1, 3, 5, 7, 8] 并不意味着整个数组都排好序了。

它只保证:最小值在最上面。

所以如果你只想反复拿"最小的那个",堆特别方便。

储存

Heap 通常用一个数组来存。

例如:

复制代码
        2
       / \
      3   5
     / \
    7   8

存成:

heap = 2, 3, 5, 7, 8

操作

push

把一个元素放进 Heap。向上调整(sift up)

假设:heap = 2, 3, 5, 7

现在加入:1

最简单的做法:直接把 1 放到数组最后。

变成:2, 3, 5, 7, 1

对应:

2

/ \

3 5

/ \

7 1

这显然不是 Heap,因为:

1 < 3

1 < 2

所以我们需要把 1 往上移动。

Sift Up

新元素现在 index = 4

它的 parent:parent = (4 - 1) // 2 = 1

所以比较:heap4 = 1 heap1 = 3

因为:1 < 3

交换:2, 1, 5, 7, 3

现在 1 在 index 1

继续找 parent:parent = (1 - 1) // 2 = 0

比较:heap0 = 2 heap1 = 1 1 < 2

交换:1, 2, 5, 7, 3

完成。

实现

python 复制代码
def push(self, x):
    self.heap.append(x)

    i = len(self.heap) - 1

    while i > 0:
        parent = (i - 1) // 2

        if self.heap[parent] <= self.heap[i]:
            break

        self.heap[parent], self.heap[i] = \
            self.heap[i], self.heap[parent]

        i = parent

把新元素放最后

看看爸爸

如果我比爸爸小

和爸爸交换

继续往上

直到爸爸比我小

pop

把 Heap 顶部,也就是最小值拿走。向下调整(sift down)

假设:

1

/ \

3 5

/ \

7 8

数组:1, 3, 5, 7, 8

现在:pop()

我们要删除 1

但这里不能直接 del heap0

因为这样后面的结构全部乱掉。

正确做法是:

  1. 把最后一个元素拿到顶部:
复制代码
        8
       / \
      3   5
     /
    7

数组:8, 3, 5, 7

然后把 8 往下沉。

Sift Down

现在 8 在 index 0

它有两个孩子:

复制代码
left = 2 * i + 1     left = 1 → 3
right = 2 * i + 2         right = 2 → 5

我们应该找两个孩子里面更小的那个交换。

因为我们是 Min Heap。

所以:3 < 5

3 换:3, 8, 5, 7

3

/ \

8 5

/

7

8 现在在 index 1

继续:

left = 3 → 7

right = 4 → 不存在

所以和 7 比,7 < 8 → 交换

3, 7, 5, 8

完成。

实现

python 复制代码
def pop(self):
    ans = self.heap[0]

    # 最后一个元素放到顶部
    self.heap[0] = self.heap[-1]
    self.heap.pop()

    i = 0

    while True:
        left = 2 * i + 1
        right = 2 * i + 2

        smallest = i

        if left < len(self.heap) and \
           self.heap[left] < self.heap[smallest]:
            smallest = left

        if right < len(self.heap) and \
           self.heap[right] < self.heap[smallest]:
            smallest = right

        if smallest == i:
            break

        self.heap[i], self.heap[smallest] = \
            self.heap[smallest], self.heap[i]

        i = smallest

    return ans

刷题

你刷 Heap 题的时候,可以先问自己:

我要维护的是 Top K 最大,还是 Top K 最小?

然后:

目标 Heap
Top K 最大 Min Heap
Top K 最小 Max Heap
不断取最小 Min Heap
不断取最大 Max Heap

这个规律非常重要。

例如:

第 K 大不是用 Max Heap!

而是:Min Heap,大小 K

因为我们需要让第 K 大卡在 Heap 的最顶端。

相关推荐
phltxy6 小时前
C语言操作符详解
java·c语言·算法
aqiu1111117 小时前
【LeetCode 902】最大为 N 的数字组合 - 详细题解与数位组合思路
数据结构·算法·leetcode·蓝桥杯·数位dp
步行cgn7 小时前
@Configuration 详解:Spring 配置类的核心注解
java·后端·spring
sunshine22 girl7 小时前
Java学习一 环境配置2 安装和基本使用Idea
java·学习·intellij-idea
辰烨chenye7 小时前
LeetCode Hot 100 题解 · 哈希篇
算法·leetcode·哈希算法
玖玥拾8 小时前
LeetCode 219 存在重复元素 II
算法·leetcode·哈希算法·散列表
ocean21038 小时前
2025-2026年AI部署与MLOps大厂面试高频问题
人工智能·面试·大模型推理·ai部署
嘿嘿-669 小时前
Windows 一键使用 GPT-6 Astra:Codex CLI 配置教程
java·人工智能·windows·gpt·chatgpt·web
策案案案10 小时前
YOLO: 将AI Agents嵌入到IntelliJ IDEA
java·大数据·人工智能·笔记·yolo·microsoft·intellij-idea