JS实现堆 & 215.数组中的第K个最大元素

解决问题

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();
};
相关推荐
wangruofeng25 分钟前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
文丑颜不良啊1 小时前
LeetCode2761~2780题目解析
java·leetcode
清晨Coding1 小时前
为什么用 React Developer Tools 查看组件树这么乱?
前端·react.js
johnjincaaaa1 小时前
猿人学第 18 题「jsvmp 洞察先机」逆向通关实录
javascript·后端
IT枫斗者枫哥2 小时前
子线程断言失败,JUnit 为什么还显示通过?
java·后端
鶴哥只手遮天2 小时前
《Electron 45.2.3 内核解剖》第 4 章 补丁体系:380 个补丁改了什么
前端·electron
考虑考虑4 小时前
JDK27中的Set.ofLazy
java·后端·java ee
FungLeo4 小时前
成为全栈·Vue 管理后台篇·分类树与标签管理:层级数据如何落到管理界面
前端·javascript·vue.js·分类树·naive ui·标签管理·前端数据结构
文丑颜不良啊4 小时前
LeetCode2841~2860题目解析
java·leetcode
小南家的青蛙4 小时前
Tomcat与Jetty深度对比
java·tomcat·jetty