题目(medium)
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
思路
优先级队列,就是一个披着队列外衣的堆。
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。
所以我们要用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| class Heap { constructor(compareFn) { this.compareFn = compareFn; this.queue = []; }
push(item) { this.queue.push(item);
let index = this.size() - 1; let parent = Math.floor((index - 1) / 2);
while (parent >= 0 && this.compare(parent, index) > 0) { [this.queue[index], this.queue[parent]] = [this.queue[parent], this.queue[index]];
index = parent; parent = Math.floor((index - 1) / 2); } }
pop() { const out = this.queue[0];
this.queue[0] = this.queue.pop();
let index = 0; let left = 1; let searchChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
while (searchChild !== undefined && this.compare(index, searchChild) > 0) { [this.queue[index], this.queue[searchChild]] = [this.queue[searchChild], this.queue[index]];
index = searchChild; left = 2 * index + 1; searchChild = this.compare(left, left + 1) > 0 ? left + 1 : left; }
return out; }
size() { return this.queue.length; }
compare(index1, index2) { if (this.queue[index1] === undefined) return 1; if (this.queue[index2] === undefined) return -1;
return this.compareFn(this.queue[index1], this.queue[index2]); }
}
const topKFrequent = function (nums, k) { const map = new Map();
for (const num of nums) { map.set(num, (map.get(num) || 0) + 1); }
const heap= new Heap((a, b) => a[1] - b[1]);
for (const entry of map.entries()) { heap.push(entry);
if (heap.size() > k) { heap.pop(); } }
const res = [];
for (let i = heap.size() - 1; i >= 0; i--) { res[i] = heap.pop()[0]; }
return res; };
|
时间复杂度:O(nlogk)。
空间复杂度:O(n)。