Skip to content

Commit 812f01a

Browse files
committed
feat: 347. 前 K 个高频元素更新小顶堆解法
1 parent 7fc5ab4 commit 812f01a

File tree

1 file changed

+94
-4
lines changed

1 file changed

+94
-4
lines changed

basic/hashmap/20.top-k-frequent-elements.md

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ https://leetcode-cn.com/problems/top-k-frequent-elements/
1212
- [思路](#思路-1)
1313
- [复杂度分析](#复杂度分析-1)
1414
- [代码](#代码-1)
15+
- [方法 3:小顶堆](#方法-3小顶堆)
16+
- [思路](#思路-2)
17+
- [复杂度分析](#复杂度分析-2)
18+
- [代码](#代码-2)
1519

1620
## 题目描述
1721

@@ -109,10 +113,10 @@ var topKFrequent = function (nums, k) {
109113
}
110114
// 入堆,格式是:[数字,次数],按次数排序
111115
const maxHeap = new MaxHeap(Object.entries(map), function comparator(
112-
target,
116+
inserted,
113117
compared,
114118
) {
115-
return target[1] < compared[1];
119+
return inserted[1] < compared[1];
116120
});
117121
// 输出前 k 个
118122
const res = [];
@@ -129,8 +133,8 @@ class Heap {
129133
this.list = list;
130134

131135
if (typeof comparator != 'function') {
132-
this.comparator = function comparator(target, compared) {
133-
return target < compared;
136+
this.comparator = function comparator(inserted, compared) {
137+
return inserted < compared;
134138
};
135139
} else {
136140
this.comparator = comparator;
@@ -194,3 +198,89 @@ class MaxHeap extends Heap {
194198
}
195199
}
196200
```
201+
202+
## 方法 3:小顶堆
203+
204+
### 思路
205+
206+
统计每个数字出现的次数后,维护一个大小为 k 的小顶堆。
207+
208+
### 复杂度分析
209+
210+
- 时间复杂度:$O(klogk)$。
211+
- 空间复杂度:$O(m)$,m 是数组中不同数字的数量,哈希表的空间,小顶堆的空间是 $O(k)$,`m >= k`
212+
213+
### 代码
214+
215+
JavaScript Code
216+
217+
```js
218+
/**
219+
* @param {number[]} nums
220+
* @param {number} k
221+
* @return {number[]}
222+
*/
223+
var topKFrequent = function (nums, k) {
224+
// 统计出现次数
225+
const map = {};
226+
for (const n of nums) {
227+
n in map || (map[n] = 0);
228+
map[n]++;
229+
}
230+
231+
const minHeap = new MinHeap([], function comparator(inserted, compared) {
232+
return inserted[1] > compared[1];
233+
});
234+
235+
// 维护一个大小为 k 的小顶堆,堆元素格式是:[数字,次数],按次数排序
236+
Object.entries(map).forEach(([num, times]) => {
237+
const [, minTimes] = minHeap.peek() || [, 0];
238+
// 小顶堆大小还没达到 k,继续插入新元素
239+
if (minHeap.size() < k) {
240+
minHeap.insert([num, times]);
241+
}
242+
243+
// 小顶堆大小为 k,如果新元素次数大于堆顶,弹出堆顶,插入新元素
244+
// 否则就不用管这个元素了
245+
else if (minHeap.size() === k && times > minTimes) {
246+
minHeap.pop();
247+
minHeap.insert([num, times]);
248+
}
249+
});
250+
251+
// 反序输出小顶堆中的所有元素
252+
const res = Array(k);
253+
while (k-- > 0) {
254+
res[k] = minHeap.pop()[0];
255+
}
256+
return res;
257+
};
258+
259+
// *************************************
260+
261+
class MinHeap extends Heap {
262+
constructor(list, comparator) {
263+
if (typeof comparator != 'function') {
264+
comparator = function comparator(inserted, compared) {
265+
return inserted > compared;
266+
};
267+
}
268+
super(list, comparator);
269+
}
270+
271+
heapify(arr, size, i) {
272+
let smallest = i;
273+
const left = Math.floor(i * 2 + 1);
274+
const right = Math.floor(i * 2 + 2);
275+
if (left < size && this.comparator(arr[smallest], arr[left]))
276+
smallest = left;
277+
if (right < size && this.comparator(arr[smallest], arr[right]))
278+
smallest = right;
279+
280+
if (smallest !== i) {
281+
[arr[smallest], arr[i]] = [arr[i], arr[smallest]];
282+
this.heapify(arr, size, smallest);
283+
}
284+
}
285+
}
286+
```

0 commit comments

Comments
 (0)