Java 数组中的第 K 个最大元素:快速选择与堆排序
一、原题回顾
题目描述:
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例:
示例 1:
输入:[3,2,1,5,6,4], k = 2
输出:5
解释:排序后为 [1,2,3,4,5,6],第 2 大的元素是 5。
示例 2:
输入:[3,2,3,1,2,4,5,5,6], k = 4
输出:4
解释:排序后为 [1,2,2,3,3,4,5,5,6],第 4 大的元素是 4(注意重复元素也要计算)。
提示:
1 ≤ k ≤ nums.length ≤ 10^5-10^4 ≤ nums[i] ≤ 10^4
二、原题分析
2.1 问题本质
我们需要在未排序的数组中找到第 k 大的元素,等价于找到排序后索引为 n-k 的元素(0-based)。
2.2 暴力解法及其局限性
方法 1:排序后取值
- 对数组进行排序(如
Arrays.sort()); - 返回
nums[n - k]。
时间复杂度:O(n log n)
空间复杂度:O(1)(原地排序)
问题:题目要求 O(n) 时间复杂度,此法不满足。
方法 2:维护大小为 k 的最小堆
- 遍历数组,维护一个大小为 k 的最小堆;
- 堆顶即为第 k 大元素。
时间复杂度:O(n log k)
空间复杂度:O(k)
问题:当 k≈n 时,退化为 O(n log n),仍不满足 O(n) 要求。
关键洞察:我们需要一种线性时间的选择算法,而非完全排序。
三、答案构思
3.1 核心思想:分治 + 快速选择
快速选择(Quickselect) 是快速排序的变种,专用于解决'第 k 小/大元素'问题。

