算法 - 数组第 K 大元素 / TopK 问题
1. 题目
给定整数数组 nums 和整数 k,返回数组中第 k 大的元素(排序后第 k 个位置的值,不是第 k 个不同元素)。
示例:
1 | 输入: nums = [3,2,1,5,6,4], k = 2 |
2. 解题思路
「第 K 大 / Top K」是超高频题型,有三种主流套路,各有适用场景。
2.1 排序法 O(n log n)
直接排序后取 nums[n - k]。简单,但不是最优,面试可作为保底并说明「有更快的」。
2.2 大小为 K 的最小堆 O(n log k) —— 求 TopK 首选
维护一个只装 k 个元素的最小堆:
- 遍历数组,堆大小 < k 就入堆。
- 否则若当前值
> 堆顶(堆里最小的),弹出堆顶、压入当前值。 - 遍历结束,堆顶就是第 k 大(堆里 k 个数中最小的那个,恰为整体第 k 大)。
优势:天然适合数据流 / 海量数据,内存只需 O(k),不必一次性拿到全部数据,这也是「TopK」在工程里(如热点搜索词)的常见解法。
2.3 快速选择(Quickselect)平均 O(n)
复用快排的 partition:每趟把基准放到最终位置 p,若 p === n-k 直接返回;否则只递归目标所在的那一半,平均线性、最坏 O(n²)(随机化 pivot 可高概率避免)。
- 时间复杂度:平均
O(n);空间O(1)(原地)。
3. TypeScript 实现
1 | // 2.3 快速选择(原地,平均 O(n)) |
4. 面试延伸
- 前 K 个高频元素(347):先哈希统计频次,再对频次跑「大小 k 的小顶堆」或快速选择,是 TopK + 堆的经典组合。
- 海量数据(如 10 亿数取前 100):绝不可能全放内存,答案就是大小为 k 的小顶堆分块处理,凸显堆相对于快选的优势。
- 第 K 小的元素 / 有序矩阵第 K 小(378):可加一条「二分答案」解法——在值域二分,用
O(n)统计<= mid的个数,O(n log(range))。 - 一定要区分:快速选择平均 O(n) 但会打乱原数组;堆法保证 O(n log k) 且能处理流式数据。选型看是否可修改原数组、是否一次性数据。
难度:中等 | LeetCode 215 题 | 堆 / 分治双高频