347.前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
示例 2:
- 输入: nums = [1], k = 1
- 输出: [1]
提示:
- 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 $O(n \log n)$ , n 是数组的大小。
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
- 你可以按任意顺序返回答案
思路: 使用小根堆
建堆注意事项:
- this.函数传入和返回的都是 下标
- 对比之前要保证 this.heap[推导的下标] 存在
- 使用条件 if(h.size() > k) 维护一个K大小的堆即可
JavaScript代码:
class MinHeap{
constructor(){
this.heap = []
}
// 交换节点
swap(i, j){
const temp = this.heap[i]
this.heap[i] = this.heap[j]
this.heap[j] = temp
}
// 获取父节点
getParentIndex(i) {
// return Math.floor((i - 1) / 2) // 拿到商
return (i - 1) >> 1
}
// 获取左子节点
getLeftIndex(i) {
return i * 2 + 1
}
// 获取右子节点
getRightIndex(i) {
return i * 2 + 2
}
// 上移操作
shiftUp(index){
if(index === 0) return
const parentIndex = this.getParentIndex(index)
if(this.heap[parentIndex] && this.heap[parentIndex].value > this.heap[index].value){
this.swap(parentIndex, index)
this.shiftUp(parentIndex)
}
}
// 下移操作
shiftDown(index){
const leftIndex = this.getLeftIndex(index)
const rightIndex = this.getRightIndex(index)
if(this.heap[leftIndex] && this.heap[leftIndex].value < this.heap[index].value){
this.swap(leftIndex, index)
this.shiftDown(leftIndex)
}
if(this.heap[rightIndex] && this.heap[rightIndex].value < this.heap[index].value){
this.swap(rightIndex, index)
this.shiftDown(rightIndex)
}
}
// 1、插入元素
insert(value){
this.heap.push(value)
this.shiftUp(this.heap.length - 1)
}
// 2、删除堆顶
pop(){
this.heap[0] = this.heap.pop()
this.shiftDown(0)
}
// 3、获取堆顶
peek(){
return this.heap[0]
}
// 4、获取堆的大小
size(){
return this.heap.length
}
}
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function (nums, k) {
const map = new Map()
nums.forEach(n => {
map.set(n, map.has(n) ? map.get(n) + 1 : 1)
})
const h = new MinHeap()
map.forEach((value, key) => {
h.insert({value, key})
if(h.size() > k){
h.pop()
}
})
return h.heap.map(a => a.key)
};