4
4
5
5
优先队列与普通队列最大的不同点在于 ** 出队顺序** 。
6
6
7
- 普通队列的出队顺序跟入队顺序相关,符合「先进先出(First in, First out)」的规则。
8
-
9
- 而优先队列的出队顺序跟入队顺序无关,优先队列是按照元素的优先级来决定出队顺序的。优先级高的元素优先出队,优先级低的元素后出队。优先队列符合 ** 「最高级先出(First in, Largest out)」** 的规则。
7
+ - 普通队列的出队顺序跟入队顺序相关,符合「先进先出(First in, First out)」的规则。
8
+ - 优先队列的出队顺序跟入队顺序无关,优先队列是按照元素的优先级来决定出队顺序的。优先级高的元素优先出队,优先级低的元素后出队。优先队列符合 ** 「最高级先出(First in, Largest out)」** 的规则。
10
9
11
10
优先队列的示例图如下所示。
12
11
16
15
17
16
优先队列的应用场景非常多,比如:
18
17
19
- - 数据压缩:赫夫曼编码算法;
20
- - 最短路径算法:Dijkstra 算法;
21
- - 最小生成树算法:Prim 算法;
22
- - 任务调度器:根据优先级执行系统任务;
23
- - 事件驱动仿真:顾客排队算法;
24
- - 选择问题 :查找第 k 个最小元素。
18
+ - ** 数据压缩** :赫夫曼编码算法;
19
+ - ** 最短路径算法** :Dijkstra 算法;
20
+ - ** 最小生成树算法** :Prim 算法;
21
+ - ** 任务调度器** :根据优先级执行系统任务;
22
+ - ** 事件驱动仿真** :顾客排队算法;
23
+ - ** 排序问题 ** :查找第 k 个最小元素。
25
24
26
25
很多语言都提供了优先级队列的实现。比如,Java 的 ` PriorityQueue ` ,C++ 的 ` priority_queue ` 等。Python 中也可以通过 ` heapq ` 来实现优先队列。下面我们来讲解一下优先队列的实现。
27
26
@@ -197,23 +196,51 @@ class PriorityQueue:
197
196
198
197
#### 5.1.2 题目大意
199
198
200
- 给定一个整数数组 ` nums ` ,再给定一个整数 ` k ` ,表示为大小为 ` k ` 的滑动窗口从数组的最左侧移动到数组的最右侧。我们只能看到滑动窗口内的 ` k ` 个数字,滑动窗口每次只能向右移动一位。
199
+ ** 描述** :给定一个整数数组 ` nums ` ,再给定一个整数 ` k ` ,表示为大小为 ` k ` 的滑动窗口从数组的最左侧移动到数组的最右侧。我们只能看到滑动窗口内的 ` k ` 个数字,滑动窗口每次只能向右移动一位。
200
+
201
+ ** 要求** :返回滑动窗口中的最大值。
202
+
203
+ ** 说明** :
201
204
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
+ ```
203
228
204
229
#### 5.1.3 解题思路
205
230
206
- 暴力求解的话,二重循环,时间复杂度为 $O(n * k)$。
231
+ 暴力求解的话,需要使用二重循环遍历,其时间复杂度为 $O(n * k)$。根据题目给定的数据范围,肯定会超时 。
207
232
208
233
我们可以使用优先队列来做。
209
234
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 . 滑动结束时,输出答案数组。
215
242
216
- #### 5.1.4 代码
243
+ ##### 思路 1: 代码
217
244
218
245
``` Python
219
246
class Solution :
@@ -231,6 +258,11 @@ class Solution:
231
258
return res
232
259
```
233
260
261
+ ##### 思路 1:复杂度分析
262
+
263
+ - ** 时间复杂度** :$O(n \times \log_2n)$。
264
+ - ** 空间复杂度** :$O(k)$。
265
+
234
266
### 5.2 前 K 个高频元素
235
267
236
268
#### 5.2.1 题目链接
@@ -239,22 +271,39 @@ class Solution:
239
271
240
272
#### 5.2.2 题目大意
241
273
242
- 给定一个整数数组 ` nums ` 和一个整数 ` k ` 。
274
+ ** 描述** :给定一个整数数组 ` nums ` 和一个整数 ` k ` 。
275
+
276
+ ** 要求** :返回出现频率前 ` k ` 高的元素。可以按任意顺序返回答案。
243
277
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
+ ```
245
294
246
295
#### 5.2.3 解题思路
247
296
248
- 1 . 使用哈希表记录下数组中各个元素的频数。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
297
+ ##### 思路 1:哈希表 + 优先队列
298
+
299
+ 1 . 使用哈希表记录下数组中各个元素的频数。
249
300
2 . 然后将哈希表中的元素去重,转换为新数组。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
250
301
3 . 使用二叉堆构建优先队列,优先级为元素频数。此时堆顶元素即为频数最高的元素。时间复杂度 $O(n)$,空间复杂度 $O(n)$。
251
302
4 . 将堆顶元素加入到答案数组中,进行出队操作。时间复杂度 $O(log{n})$。
252
303
- 出队操作:交换堆顶元素与末尾元素,将末尾元素已移出堆。继续调整大顶堆。
253
304
5 . 不断重复第 4 步,直到 ` k ` 次结束。调整 ` k ` 次的时间复杂度 $O(nlog{n})$。
254
305
255
- 所以总体时间复杂度 $O(nlog{n})$。
256
-
257
- #### 5.2.4 代码
306
+ ##### 思路 1:代码
258
307
259
308
``` Python
260
309
class Heapq :
@@ -339,6 +388,11 @@ class Solution:
339
388
return res
340
389
```
341
390
391
+ ##### 思路 1:复杂度分析
392
+
393
+ - ** 时间复杂度** :$O(n \times \log_2n)$。
394
+ - ** 空间复杂度** :$O(n)$。
395
+
342
396
## 参考资料
343
397
344
398
- 【博文】[ 浅入浅出数据结构(15)—— 优先队列(堆) - NSpt - 博客园] ( https://www.cnblogs.com/mm93/p/7481782.html )
0 commit comments