Leetcode: 数组中的第K个最大元素

38 阅读2分钟

原题:leetcode.cn/problems/kt…

题目描述

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

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

解题思路

  1. 快速选择算法
    • 随机化分区:选取随机pivot将数组分为大于/小于pivot的两部分
    • 分治策略:根据pivot位置与k的关系,递归处理左或右子数组
    • 终止条件:pivot正好是第k大元素时返回
  2. 堆排序优化
    • 构建大小为k的最小堆
    • 遍历数组,维护堆顶为当前第k大元素
    • 最终堆顶即为结果

关键洞察

  1. 快速选择本质:快速排序的变种,但只需处理目标所在分区
  2. 随机化避免最坏:随机选择pivot防止有序数组的O(n²)退化
  3. 堆的适用场景:海量数据流场景(空间效率高)
  4. 索引转换:第k大元素下标 = n - k(升序排序)

复杂度分析

方法时间复杂度空间复杂度
快速选择平均O(n),最坏O(n²)递归栈O(log n)
堆方法O(n log k)O(k)
排序法O(n log n)O(1)

最优选择

  • 常规场景:快速选择(平均线性时间)
  • 内存受限:堆方法(仅需O(k)空间)
  • 巨量数据流:堆方法是唯一可行解

代码实现

/**
 * @link {https://leetcode.cn/problems/kth-largest-element-in-an-array}
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var findKthLargest = function (nums, k) {
    const quickSelect = (num, l, r, k) => {
        if (l === r) return num[k];

        const x = num[l];
        let i = l - 1, j = r + 1;

        while (i < j) {
            do i++; while (num[i] < x);
            do j--; while (num[j] > x);
            if (i < j) {
                [num[i], num[j]] = [num[j], num[i]]
            }
        }

        if (k <= j) {
            return quickSelect(num, l, j, k);
        } else {
            return quickSelect(num, j + 1, r, k);
        }
    }

    const n = nums.length;
    return quickSelect(nums, 0, n - 1, n - k);
};

相似题目