解决问题
215.数组中的第K个最大元素

最小堆(MinHeap)实现
核心性质: 父节点的值始终 <= 子节点的值,堆顶(index 0)永远是全局最小值。
底层结构: 用数组模拟完全二叉树,父子节点索引关系:
- 父节点:(i - 1) / 2
- 左子节点:2 * i + 1
- 右子节点:2 * i + 2
时间复杂度:
- push:O(log n) ------ 插入后上浮
- pop:O(log n) ------ 删除堆顶后下沉
- peek:O(1) ------ 直接读堆顶
核心操作说明:
- bubbleUp(上浮):新元素插入到数组末尾后,如果比父节点小,就和父节点交换,一路向上直到满足堆性质。
- sinkDown(下沉):堆顶被替换后,如果比子节点大,就和较小的子节点交换,一路向下直到满足堆性质。
- push(插入):放到数组末尾,然后上浮到正确位置。
- pop(弹出):取出堆顶 → 把数组最后一个元素移到堆顶 → 对新堆顶执行下沉操作。
- peek(查看):直接返回堆顶(最小值),不弹出。
典型用法: 维护一个大小为 k 的最小堆,堆顶就是"最大的 k 个元素中的最小值",即第 k 大元素。遍历数组时,元素入堆,堆大小超过 k 就弹出堆顶(淘汰最小值),最终堆顶就是答案。
js
class Heap {
constructor() {
this.heap = [];
}
bubbleUp(index) {
let i = index;
while(i > 0) {
const parent = Math.floor((i - 1) / 2);
if (this.heap[i] < this.heap[parent]) {
[this.heap[i], this.heap[parent]] = [this.heap[parent], this.heap[i]];
i = parent;
} else {
break
}
}
}
sinkDown(index) {
while(true) {
let smallestIndex = index;
const left = 2 * index + 1;
const right = 2 * index + 2;
if (left < this.heap.length && this.heap[smallestIndex] > this.heap[left]) {
smallestIndex = left;
}
if (right < this.heap.length && this.heap[smallestIndex] > this.heap[right]) {
smallestIndex = right;
}
if (smallestIndex !== index) {
[this.heap[smallestIndex], this.heap[index]] = [this.heap[index], this.heap[smallestIndex]];
index = smallestIndex;
} else {
break;
}
}
}
push(val) {
this.heap.push(val);
this.bubbleUp(this.heap.length - 1);
}
pop() {
const top = this.heap[0];
const last = this.heap.pop();
if (this.heap.length) {
this.heap[0] = last;
this.sinkDown(0);
}
return top;
}
peek() {
return this.heap[0];
}
}
数组中的第K个最大元素解题方案为
js
// 堆
function findKthLargest(nums: number[], k: number): number {
class MinHeap {
heap: number[];
constructor() {
this.heap = [];
}
bubbleUp(index) {
let i = index;
while (i > 0) {
const parent = Math.floor((i - 1) / 2);
if (this.heap[i] < this.heap[parent]) {
[this.heap[i], this.heap[parent]] = [this.heap[parent], this.heap[i]];
i = parent;
} else {
break
}
}
}
sinkDown(index) {
while (true) {
let smallestIndex = index;
const left = 2 * index + 1;
const right = 2 * index + 2;
if (left < this.heap.length && this.heap[smallestIndex] > this.heap[left]) {
smallestIndex = left;
}
if (right < this.heap.length && this.heap[smallestIndex] > this.heap[right]) {
smallestIndex = right;
}
if (smallestIndex !== index) {
[this.heap[smallestIndex], this.heap[index]] = [this.heap[index], this.heap[smallestIndex]];
index = smallestIndex;
} else {
break;
}
}
}
push(val) {
this.heap.push(val);
this.bubbleUp(this.heap.length - 1);
}
pop() {
const top = this.heap[0];
const last = this.heap.pop();
if (this.heap.length) {
this.heap[0] = last;
this.sinkDown(0);
}
return top;
}
peek() {
return this.heap[0];
}
size() {
return this.heap.length;
}
}
const heap = new MinHeap();
nums.forEach((item) => {
heap.push(item);
if (heap.size() > k) {
heap.pop();
}
});
return heap.peek();
};