LeetCode刷题指南
第 0 章 hot100
0.1 哈希
0.2 双指针
0.3 滑动窗口
0.4 子串
0.5 普通数组
0.6 矩阵
0.7 链表
0.8 二叉树
0.9 图论
0.10 回溯
0.11 二分查找
0.12 栈
0.13 堆
0.14 贪心算法
0.15 动态规划
0.16 多维动态规划
0.17 技巧
第0-1章 面试经典150
0.1 数组/字符串
0.2 双指针
0.3 滑动窗口
链表
二叉树
第 1 章 最易懂的贪心算法
1.1 算法解释
1.2 分配问题
1.3 区间问题
1.4 练习
第 2 章 玩转双指针
2.1 算法解释
2.2 Two Sum
2.3 归并两个有序数组
2.4 滑动窗口
2.5 快慢指针
2.6 练习
第 3 章 居合斩!二分查找
3.1 算法解释
3.2 求开方
3.3 查找区间
3.4 查找峰值
3.5 旋转数组查找数字
3.6 练习
第 4 章 千奇百怪的排序算法
4.1 常用排序算法
4.2 快速选择
4.3 桶排序
4.4 练习
第 5 章 一切皆可搜索
5.1 算法解释
5.2 深度优先搜索
5.3 回溯法
5.4 广度优先搜索
5.5 练习
第 6 章 深入浅出动态规划
6.1 算法解释
6.2 基本动态规划:一维
6.3 基本动态规划:二维
6.4 分割类型题
6.5 子序列问题
6.6 背包问题
6.7 字符串编辑
6.8 股票交易
6.9 练习
第 7 章 化繁为简的分治法
7.1 算法解释
7.2 表达式问题
7.3 练习
第 8 章 巧解数学问题
8.1 引言
8.2 公倍数与公因数
8.3 质数
8.4 数字处理
8.5 随机与取样
8.6 练习
第 9 章 神奇的位运算
9.1 常用技巧
9.2 位运算基础问题
9.3 二进制特性
9.4 练习
第 10 章 妙用数据结构
10.1 C++ STL
10.2 Python 常用数据结构
10.3 数组
10.4 栈和队列
10.5 单调栈
10.6 优先队列
10.7 双端队列
10.8 哈希表
10.9 多重集合和映射
10.10 前缀和与积分图
10.11 练习
第 11 章 令人头大的字符串
11.1 引言
11.2 字符串比较
11.3 字符串理解
11.4 字符串匹配
11.5 练习
第 12 章 指针三剑客之一:链表
12.1 数据结构介绍
12.2 链表的基本操作
12.3 其它链表技巧
12.4 练习
第 13 章 指针三剑客之二:树
13.1 数据结构介绍
13.2 树的递归
13.3 层次遍历
13.4 前中后序遍历
13.5 二叉查找树
13.6 字典树
13.7 练习
第 14 章 指针三剑客之三:图
14.1 数据结构介绍
14.2 二分图
14.3 拓扑排序
14.4 练习
第 15 章 更加复杂的数据结构
15.1 引言
15.2 并查集
15.3 复合数据结构
15.4 练习
第16章 面试题
第 17 章 十大经典排序算法
README
本文档使用 MrDoc 发布
-
+
首页
10.6 优先队列
# 10.6 优先队列 `优先队列`(priority queue)可以在 $O(1)$ 时间内获得最大值,并且可以在 O(log n) 时间内取出最大值或插入任意值。 <figure> <span style={{ display: 'block', width: '50%', margin: '0 auto' }}>  </span> <figcaption style={{ textAlign: 'center' }}>图 10.2: (最大)堆,维护的是数据结构中的大于关系</figcaption> </figure> 优先队列常常用堆(heap)来实现。堆是一个完全二叉树,其每个节点的值总是大于等于子节点的值。实际实现堆时,我们通常用一个数组而不是用指针建立一个树。这是因为堆是完全二叉树,所以用数组表示时,位置 i 的节点的父节点位置一定为 (i-1)/2,而它的两个子节点的位置又一定分别为 2i+1 和 2i+2。 以下是堆的实现方法,其中最核心的两个操作是上浮和下沉:如果一个节点比父节点大,那么需要交换这个两个节点;交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操作,我们称之为上浮;类似地,如果一个节点比父节小,也需要不断地向下进行比较和交换操作我们称之为下沉。如果一个节点有两个子节点,我们总是交换最大的子节点。 ```py class Heap: def __init__(self): self.heap = [] # 上浮。 def swim(self, pos: int): next_pos = (pos - 1) // 2 while pos > 0 and self.heap[next_pos] < self.heap[pos]: self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] pos = next_pos next_pos = (pos - 1) // 2 # 下沉。 def sink(self, pos: int): n = len(self.heap) next_pos = 2 * pos + 1 while next_pos < n: if next_pos < n - 1 and self.heap[next_pos] < self.heap[next_pos + 1]: next_pos += 1 if self.heap[pos] >= self.heap[next_pos]: break self.heap[next_pos], self.heap[pos] = self.heap[pos], self.heap[next_pos] pos = next_pos next_pos = 2 * pos + 1 # 插入任意值:把新的数字放在最后一位,然后上浮。 def push(self, k: int): self.heap.append(k) self.swim(len(self.heap) - 1) # 删除最大值:把最后一个数字挪到开头,然后下沉。 def pop(self): self.heap[0] = self.heap.pop() self.sink(0) # 获得最大值。 def top(self) -> int: return self.heap[0] ``` 通过将算法中的大于号和小于号互换,我们也可以得到一个快速获得最小值的优先队列。 ## [23. Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/) ### 题目描述 给定 k 个增序的链表,试将它们合并成一条增序链表。 ### 输入输出样例 输入是一个一维数组,每个位置存储链表的头节点;输出是一条链表。 ``` Input: [1->4->5, 1->3->4, 2->6] Output: 1->1->2->3->4->4->5->6 ``` ### 题解 本题可以有很多中解法,比如类似于归并排序进行两两合并。我们这里展示一个速度比较快的方法,即把所有的链表存储在一个优先队列中,每次提取所有链表头部节点值最小的那个节点,直到所有链表都被提取完为止。 因为 C++ priority_queue 的比较函数默认是对最大堆进行比较并维持递增关系,如果我们想要获取最小的节点值,我们则需要实现一个最小堆。因此堆的比较函数应该维持递减关系,即 lambda 函数中返回时用大于号而不是递增关系时的小于号进行比较。 ```py def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]: pq = [] for idx, l in enumerate(lists): if l is not None: # ListNode不可被哈希,所以这里我们直接记录它在lists中的位置。 pq.append((l.val, idx)) heapq.heapify(pq) dummy = ListNode() cur = dummy while len(pq) > 0: _, l_idx = heapq.heappop(pq) cur.next = lists[l_idx] cur = cur.next if cur.next is not None: lists[l_idx] = lists[l_idx].next heapq.heappush(pq, (cur.next.val, l_idx)) return dummy.next ``` ## [218. The Skyline Problem](https://leetcode.com/problems/the-skyline-problem/) ### 题目描述 给定建筑物的起止位置和高度,返回建筑物轮廓(天际线)的拐点。 ### 输入输出样例 输入是一个二维整数数组,表示每个建筑物的 [左端, 右端, 高度];输出是一个二维整数数组,表示每个拐点的横纵坐标。 <figure> <span style={{ display: 'block', width: '90%', margin: '0 auto' }}>  </span> <figcaption style={{ textAlign: 'center' }}>图 10.3: 题目 218 - 建筑物及其天际线样例</figcaption> </figure> ``` Input: [[2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8]] Output: [[2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0]] ``` ### 题解 我们可以使用优先队列储存每个建筑物的高度和右端(这里使用 pair,其默认比较函数是先比较第一个值,如果相等则再比较第二个值),从而获取目前会拔高天际线、且妨碍到前一个建筑物(的右端端点)的下一个建筑物。 因为 Python 中 heapq 是最小堆,所以我们在存值的时候可以存负值,这样就变成了最大堆。 这道题比较复杂,如果实在难以理解,建议读者暂时跳过此题,或者在纸上举例子画一画。 ```py def getSkyline(buildings: List[List[int]]) -> List[List[int]]: skyline = [] pq = [] # <负高度,右端> heapq.heapify(pq) i, n = 0, len(buildings) while i < n or len(pq) > 0: if len(pq) == 0 or (i < n and buildings[i][0] <= pq[0][1]): cur_x = buildings[i][0] while i < n and cur_x == buildings[i][0]: heapq.heappush(pq, (-buildings[i][2], buildings[i][1])) i += 1 else: cur_x = pq[0][1] while len(pq) > 0 and cur_x >= pq[0][1]: heapq.heappop(pq) cur_h = -pq[0][0] if len(pq) > 0 else 0 if len(skyline) == 0 or cur_h != skyline[-1][1]: skyline.append([cur_x, cur_h]) return skyline ```
嘉心糖糖
2025年3月11日 19:36
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码