侧边栏壁纸
博主头像
Fonda's Lab 博主等级

关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。

  • 累计撰写 49 篇文章
  • 累计创建 27 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

数组中的第 K 个最大元素(LeetCode215)

LouisFonda
2024-05-22 / 0 评论 / 0 点赞 / 10 阅读 / 0 字 / 正在检测是否收录...

数组中的第 K 个最大元素(LeetCode215)

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

问题描述

需要找到排序后数组中的第 k 个最大的元素,而不是第 k 个不同的元素。要求设计并实现时间复杂度为 O(n) 的算法解决此问题。

方法1:快速选择算法(Quickselect)

快速选择算法是快速排序的一种变体,能够在平均情况下达到 O(n) 的时间复杂度。其核心思想是基于快速排序的分区思想,通过一次分区将数组分为两部分,然后判断第 k 大元素在哪一部分,递归或迭代进行选择。

实现步骤:

  1. 随机选择一个基准元素,并将数组分为大于和小于基准的两部分。
  2. 判断基准元素的位置与 k 的关系。
  3. 递归或迭代在适当的部分继续查找,直到找到第 k 大的元素。

代码实现:

const findKthLargest = function(nums, k) {
    const partition = (left, right) => {
        const pivot = nums[right];
        let pIndex = left;
        for (let i = left; i < right; i++) {
            if (nums[i] >= pivot) {
                [nums[i], nums[pIndex]] = [nums[pIndex], nums[i]];
                pIndex++;
            }
        }
        [nums[pIndex], nums[right]] = [nums[right], nums[pIndex]];
        return pIndex;
    };

    let left = 0, right = nums.length - 1, index = nums.length - k;
    while (left <= right) {
        const pivotIndex = partition(left, right);
        if (pivotIndex === index) {
            return nums[pivotIndex];
        } else if (pivotIndex < index) {
            left = pivotIndex + 1;
        } else {
            right = pivotIndex - 1;
        }
    }
};

方法2:最小堆

最小堆是一种完全二叉树,堆中每个节点的值都小于或等于其子节点的值。通过维护一个大小为 k 的最小堆,可以确保堆顶元素始终是当前最大的 k 个元素中的最小值。

实现步骤:

  1. 构建最小堆:使用数组实现最小堆。
  2. 遍历数组:将每个元素添加到最小堆中。
  3. 保持堆的大小为 k:如果堆的大小超过 k,则删除堆顶元素(最小元素)。
  4. 返回堆顶元素:遍历结束后,堆顶元素即为第 k 大的元素。
class MinHeap {
    constructor() {
        this.heap = [];
    }

    size() {
        return this.heap.length;
    }

    peek() {
        return this.heap[0];
    }

    insert(value) {
        this.heap.push(value);
        this.heapifyUp();
    }

    remove() {
        if (this.size() === 1) {
            return this.heap.pop();
        }
        const root = this.heap[0];
        this.heap[0] = this.heap.pop();
        this.heapifyDown();
        return root;
    }

    heapifyUp() {
        let index = this.size() - 1;
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            if (this.heap[parentIndex] <= this.heap[index]) break;
            [this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
            index = parentIndex;
        }
    }

    heapifyDown() {
        let index = 0;
        const length = this.size();
        const element = this.heap[0];
        while (true) {
            let leftChildIndex = 2 * index + 1;
            let rightChildIndex = 2 * index + 2;
            let leftChild, rightChild;
            let swap = null;

            if (leftChildIndex < length) {
                leftChild = this.heap[leftChildIndex];
                if (leftChild < element) {
                    swap = leftChildIndex;
                }
            }

            if (rightChildIndex < length) {
                rightChild = this.heap[rightChildIndex];
                if ((swap === null && rightChild < element) || (swap !== null && rightChild < leftChild)) {
                    swap = rightChildIndex;
                }
            }

            if (swap === null) break;
            [this.heap[index], this.heap[swap]] = [this.heap[swap], this.heap[index]];
            index = swap;
        }
    }
}

const findKthLargest = function(nums, k) {
    const minHeap = new MinHeap();
  
    for (let num of nums) {
        minHeap.insert(num);
        if (minHeap.size() > k) {
            minHeap.remove();
        }
    }
  
    return minHeap.peek();
};

// 示例测试
console.log(findKthLargest([3,2,1,5,6,4], 2)); // 输出: 5
console.log(findKthLargest([3,2,3,1,2,4,5,5,6], 4)); // 输出: 4

方法3:库函数

使用 JavaScript 的内置排序方法 Array.sort 和 slice 进行排序和切片,直接返回第 k 大的元素。虽然这种方法简单,但时间复杂度为 O(n log n),不满足题目要求的 O(n)。

代码实现:

const findKthLargest = function(nums, k) {
    nums.sort((a, b) => b - a);
    return nums[k - 1];
};


总结

本文介绍了三种方法来解决数组中的第 k 个最大元素问题:快速选择算法、最小堆和库函数。快速选择算法和最小堆都能在平均情况下达到 O(n) 的时间复杂度,而使用库函数的排序方法虽然简单,但时间复杂度为 O(n log n)。根据具体需求选择合适的方法进行实现。

0

评论区