关键词:TopK / 排序 / 堆 / 快速选择
核心思想:在正确的地方,用合适的数据结构和算法
一、题目回顾
给定一个整数数组 nums 和整数 k,请返回数组中 第 k 大的元素。
注意:
不是第 k 个不同的元素,而是排序后的第 k 大
示例:
nums = [3,2,1,5,6,4], k = 2
输出:5
二、解题思路总览(先立大局)
这是一个经典的 TopK 问题,常见解法有三类:
| 方法 | 思想 | 适合场景 |
|---|---|---|
| 排序 | 全局有序 | 简单直接 |
| 堆 | 维护 TopK | 工程常用 |
| 快速选择 | 局部排序 | 算法最优 |
下面我们按 由浅入深 的顺序逐一分析。
三、方法一:直接排序(最直观)
思路
- 对数组排序
- 返回下标为
nums.length - k的元素
代码示例
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
}
复杂度分析
- 时间复杂度:
O(n log n) - 空间复杂度:
O(1)(原地排序)
优缺点分析
✅ 优点
- 思路简单
- 代码最少
- 适合快速写对
❌ 缺点
- 排序了“所有元素”,而我们只关心一个
- 不满足进阶要求
👉 更像“新手解法”,但在面试里能保底
四、方法二:堆(工程向最优解)
核心思想
用一个 大小为 k 的小顶堆
始终维护数组中最大的 k 个元素
为什么是小顶堆?
- 堆顶 = 当前第 k 大
- 新元素更大 → 顶掉堆顶
- 小元素 → 自动淘汰
代码示例(小顶堆)
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int num : nums) {
pq.add(num);
if (pq.size() > k) {
pq.poll();
}
}
return pq.peek();
}
}
复杂度分析
- 时间复杂度:
O(n log k) - 空间复杂度:
O(k)
优缺点分析
✅ 优点
- 不需要排序全部数据
- 稳定、好写、好理解
- 实际工程中非常常见
❌ 缺点
- 需要额外空间
- 时间复杂度不是理论最优
👉 这是“工程友好型解法”
五、方法三:快速选择(算法天花板)
核心思想(一句话)
利用快速排序的分区思想,每次只递归一边
这不是完整的快速排序,而是:
Quick Select(快速选择)
关键认知升级
-
排序是“把所有人排好”
-
快速选择是:
- 每次确定一个元素的最终位置
- 如果不是目标 → 丢掉一半空间
代码示例(随机化 Quick Select)
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, k);
}
private int quickSelect(int[] nums, int l, int r, int k) {
int pivotIndex = partition(nums, l, r);
if (pivotIndex == k - 1) {
return nums[pivotIndex];
} else if (pivotIndex > k - 1) {
return quickSelect(nums, l, pivotIndex - 1, k);
} else {
return quickSelect(nums, pivotIndex + 1, r, k);
}
}
private int partition(int[] nums, int l, int r) {
int pivot = nums[r];
int i = l;
for (int j = l; j < r; j++) {
if (nums[j] > pivot) {
swap(nums, i++, j);
}
}
swap(nums, i, r);
return i;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
复杂度分析
| 情况 | 时间复杂度 |
|---|---|
| 平均 | O(n) |
| 最坏 | O(n²)(随机化可规避) |
空间复杂度:O(1)
优缺点分析
✅ 优点
- 理论最优
- 原地算法
- 面试官非常喜欢
❌ 缺点
- 实现复杂
- 边界容易出错
- 不适合临场硬写
👉 这是“算法能力的分水岭解法”
六、三种方法对比总结
| 方法 | 时间复杂度 | 空间 | 特点 | 推荐指数 |
|---|---|---|---|---|
| 排序 | O(n log n) | O(1) | 最简单 | ⭐⭐ |
| 小顶堆 | O(n log k) | O(k) | 工程常用 | ⭐⭐⭐⭐ |
| 快速选择 | O(n) | O(1) | 算法最优 | ⭐⭐⭐⭐⭐ |
七、选哪种?
- ✅ 写得快、保正确 → 排序
- ✅ 工程实践 / 数据流 / 大数据 → 堆
- ✅ 追求最优复杂度 / 算法面试 → 快速选择
八、一句话总结
TopK 问题不是只会一种解法,
而是根据场景,
在“简单、稳定、最优”之间做权衡。