@@ -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