Skip to content

Commit ee45813

Browse files
committed
Update 01.Priority-Queue.md
1 parent 62e4465 commit ee45813

File tree

1 file changed

+78
-24
lines changed

1 file changed

+78
-24
lines changed

Contents/04.Queue/02.Priority-Queue/01.Priority-Queue.md

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
55
优先队列与普通队列最大的不同点在于 **出队顺序**
66

7-
普通队列的出队顺序跟入队顺序相关,符合「先进先出(First in, First out)」的规则。
8-
9-
而优先队列的出队顺序跟入队顺序无关,优先队列是按照元素的优先级来决定出队顺序的。优先级高的元素优先出队,优先级低的元素后出队。优先队列符合 **「最高级先出(First in, Largest out)」** 的规则。
7+
- 普通队列的出队顺序跟入队顺序相关,符合「先进先出(First in, First out)」的规则。
8+
- 优先队列的出队顺序跟入队顺序无关,优先队列是按照元素的优先级来决定出队顺序的。优先级高的元素优先出队,优先级低的元素后出队。优先队列符合 **「最高级先出(First in, Largest out)」** 的规则。
109

1110
优先队列的示例图如下所示。
1211

@@ -16,12 +15,12 @@
1615

1716
优先队列的应用场景非常多,比如:
1817

19-
- 数据压缩:赫夫曼编码算法;
20-
- 最短路径算法:Dijkstra 算法;
21-
- 最小生成树算法:Prim 算法;
22-
- 任务调度器:根据优先级执行系统任务;
23-
- 事件驱动仿真:顾客排队算法;
24-
- 选择问题:查找第 k 个最小元素。
18+
- **数据压缩**:赫夫曼编码算法;
19+
- **最短路径算法**:Dijkstra 算法;
20+
- **最小生成树算法**:Prim 算法;
21+
- **任务调度器**:根据优先级执行系统任务;
22+
- **事件驱动仿真**:顾客排队算法;
23+
- **排序问题**:查找第 k 个最小元素。
2524

2625
很多语言都提供了优先级队列的实现。比如,Java 的 `PriorityQueue`,C++ 的 `priority_queue` 等。Python 中也可以通过 `heapq` 来实现优先队列。下面我们来讲解一下优先队列的实现。
2726

@@ -197,23 +196,51 @@ class PriorityQueue:
197196

198197
#### 5.1.2 题目大意
199198

200-
给定一个整数数组 `nums`,再给定一个整数 `k`,表示为大小为 `k` 的滑动窗口从数组的最左侧移动到数组的最右侧。我们只能看到滑动窗口内的 `k` 个数字,滑动窗口每次只能向右移动一位。
199+
**描述**:给定一个整数数组 `nums`,再给定一个整数 `k`,表示为大小为 `k` 的滑动窗口从数组的最左侧移动到数组的最右侧。我们只能看到滑动窗口内的 `k` 个数字,滑动窗口每次只能向右移动一位。
200+
201+
**要求**:返回滑动窗口中的最大值。
202+
203+
**说明**
201204

202-
要求:返回滑动窗口中的最大值。
205+
- $1 \le nums.length \le 10^5$。
206+
- $-10^4 \le nums[i] \le 10^4$。
207+
- $1 \le k \le nums.length$。
208+
209+
**示例**
210+
211+
```Python
212+
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
213+
输出:[3,3,5,5,6,7]
214+
解释:
215+
滑动窗口的位置 最大值
216+
--------------- -----
217+
[1 3 -1] -3 5 3 6 7 3
218+
1 [3 -1 -3] 5 3 6 7 3
219+
1 3 [-1 -3 5] 3 6 7 5
220+
1 3 -1 [-3 5 3] 6 7 5
221+
1 3 -1 -3 [5 3 6] 7 6
222+
1 3 -1 -3 5 [3 6 7] 7
223+
224+
225+
输入:nums = [1], k = 1
226+
输出:[1]
227+
```
203228

204229
#### 5.1.3 解题思路
205230

206-
暴力求解的话,二重循环,时间复杂度为 $O(n * k)$。
231+
暴力求解的话,需要使用二重循环遍历,其时间复杂度为 $O(n * k)$。根据题目给定的数据范围,肯定会超时
207232

208233
我们可以使用优先队列来做。
209234

210-
- 初始的时候将前 `k` 个元素加入优先队列的二叉堆中。存入优先队列的是数组值和索引的元组。优先队列将数组值作为优先级。
211-
- 然后滑动窗口从第 `k` 个元素开始遍历,将当前数组值和索引的元组插入到二叉堆中。
212-
- 当二叉堆堆顶元素的索引已经不在滑动窗口的范围中时,即 `q[0][1] <= i - k` 时,不断删除堆顶元素,直到最大值元素的索引在滑动窗口的范围中。
213-
- 将最大值加入到答案数组中,继续滑动。
214-
- 最后遍历完输出答案数组。
235+
##### 思路 1:优先队列
236+
237+
1. 初始的时候将前 `k` 个元素加入优先队列的二叉堆中。存入优先队列的是数组值与索引构成的元组。优先队列将数组值作为优先级。
238+
2. 然后滑动窗口从第 `k` 个元素开始遍历,将当前数组值和索引的元组插入到二叉堆中。
239+
3. 当二叉堆堆顶元素的索引已经不在滑动窗口的范围中时,即 `q[0][1] <= i - k` 时,不断删除堆顶元素,直到最大值元素的索引在滑动窗口的范围中。
240+
4. 将最大值加入到答案数组中,继续向右滑动。
241+
5. 滑动结束时,输出答案数组。
215242

216-
#### 5.1.4 代码
243+
##### 思路 1:代码
217244

218245
```Python
219246
class Solution:
@@ -231,6 +258,11 @@ class Solution:
231258
return res
232259
```
233260

261+
##### 思路 1:复杂度分析
262+
263+
- **时间复杂度**:$O(n \times \log_2n)$。
264+
- **空间复杂度**:$O(k)$。
265+
234266
### 5.2 前 K 个高频元素
235267

236268
#### 5.2.1 题目链接
@@ -239,22 +271,39 @@ class Solution:
239271

240272
#### 5.2.2 题目大意
241273

242-
给定一个整数数组 `nums` 和一个整数 `k`
274+
**描述**:给定一个整数数组 `nums` 和一个整数 `k`
275+
276+
**要求**:返回出现频率前 `k` 高的元素。可以按任意顺序返回答案。
243277

244-
要求:返回出现频率前 `k` 高的元素。可以按任意顺序返回答案。
278+
**说明**
279+
280+
- $1 \le nums.length \le 10^5$。
281+
- $k$ 的取值范围是 $[1, 数组中不相同的元素的个数]$。
282+
- 题目数据保证答案唯一,换句话说,数组中前 $k$ 个高频元素的集合是唯一的。
283+
284+
**示例**
285+
286+
```Python
287+
输入: nums = [1,1,1,2,2,3], k = 2
288+
输出: [1,2]
289+
290+
291+
输入: nums = [1], k = 1
292+
输出: [1]
293+
```
245294

246295
#### 5.2.3 解题思路
247296

248-
1. 使用哈希表记录下数组中各个元素的频数。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
297+
##### 思路 1:哈希表 + 优先队列
298+
299+
1. 使用哈希表记录下数组中各个元素的频数。
249300
2. 然后将哈希表中的元素去重,转换为新数组。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
250301
3. 使用二叉堆构建优先队列,优先级为元素频数。此时堆顶元素即为频数最高的元素。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
251302
4. 将堆顶元素加入到答案数组中,进行出队操作。时间复杂度 $O(log{n})$。
252303
- 出队操作:交换堆顶元素与末尾元素,将末尾元素已移出堆。继续调整大顶堆。
253304
5. 不断重复第 4 步,直到 `k` 次结束。调整 `k` 次的时间复杂度 $O(nlog{n})$。
254305

255-
所以总体时间复杂度 $O(nlog{n})$。
256-
257-
#### 5.2.4 代码
306+
##### 思路 1:代码
258307

259308
```Python
260309
class Heapq:
@@ -339,6 +388,11 @@ class Solution:
339388
return res
340389
```
341390

391+
##### 思路 1:复杂度分析
392+
393+
- **时间复杂度**:$O(n \times \log_2n)$。
394+
- **空间复杂度**:$O(n)$。
395+
342396
## 参考资料
343397

344398
- 【博文】[浅入浅出数据结构(15)—— 优先队列(堆) - NSpt - 博客园](https://www.cnblogs.com/mm93/p/7481782.html)

0 commit comments

Comments
 (0)