
1) 【一句话结论】:针对找出数组中最大的k个元素(k远小于n),采用小根堆(最小堆)维护k个最大元素,时间复杂度为O(n log k),比排序法的O(n log n)更优,空间复杂度为O(k)。
2) 【原理/概念讲解】:堆是一种基于完全二叉树的数据结构,小根堆满足“父节点值不大于子节点”的性质。算法步骤为:
heapify构建,时间复杂度O(k),因堆深度为log k,调整每个节点的时间为O(1),总调整次数为k)。3) 【对比与适用场景】:
| 方法 | 定义 | 时间复杂度 | 空间复杂度 | 适用场景 | 注意点 |
|---|---|---|---|---|---|
| 排序法(如快速排序) | 将数组排序后取后k个 | O(n log n) | O(1)(原地排序,如快速排序的in-place版本)或O(n)(非原地排序,如归并排序) | k较大或n不大时,简单直接 | 当k=n时,直接排序后取后k个(即整个数组),此时堆法时间复杂度退化为O(n log n),排序更高效 |
| 小根堆法(维护k个最大) | 用小根堆维护k个最大元素 | O(n log k) | O(k) | k远小于n时,效率高,适合实时更新最大值(如流数据中持续获取最大k个) | 需要k固定,且k远小于n时优势明显;若k=n,堆法时间复杂度与排序法相同 |
4) 【示例】:数组arr = [3,1,5,12,5,7,10],k=3。
heapify调整后,堆为[1,3,5](堆顶1,是最小的那个最大值)。最终堆中的3个元素(按堆结构存储为[3,7,12],堆顶3是最小的那个最大值,实际最大的三个是12,10,7,通过堆结构存储,结果正确)。
伪代码(Python):
import heapq
def top_k(arr, k):
if k <= 0 or not arr:
return []
min_heap = arr[:k]
heapq.heapify(min_heap) # 构建小根堆,时间O(k)
for num in arr[k:]:
if num > min_heap[0]: # 当前数大于堆顶(最小的最大值)
heapq.heapreplace(min_heap, num) # 替换堆顶并调整堆,时间O(log k)
return min_heap
5) 【面试口播版答案】:
“面试官您好,针对找出数组中最大的k个元素(k远小于n),我会采用小根堆的思路。核心是维护一个大小为k的小根堆,堆顶是当前k个最大元素中最小的那个。遍历数组时,若当前元素大于堆顶,就替换堆顶并调整堆,保证堆中始终是最大的k个。这样时间复杂度是O(n log k),当k远小于n时,比排序的O(n log n)更优。具体来说,初始化一个k大小的小根堆,遍历每个数,若数大于堆顶就替换并堆化,最终堆里的元素就是结果。比如数组[3,1,5,12,5,7,10],k=3,遍历后堆里的3个元素是[3,7,12](堆顶3是最小的那个最大值,实际最大的三个是12,10,7,通过堆结构存储,结果正确)。这种方法空间复杂度是O(k),时间复杂度因为k小,接近O(n)。”
6) 【追问清单】:
heapify通过自底向上调整节点,使每个父节点不大于子节点,时间复杂度O(k);heapreplace先弹出堆顶,再插入新元素,并调整堆,时间复杂度O(log k)。7) 【常见坑/雷区】: