找出无序数组中第 K 个最小元素
说实话,这类题目虽然常见,但你要是直接在面试里就甩出 heapq.nsmallest(),面试官八成会说一句:“你就记住了个库函数?”我不是说不能用,而是你得知道为啥这么用,背后的逻辑得讲得出来。否则,人家凭啥信你真的理解了?
咱们来认真聊一下这个问题,顺带看看有哪些更合适的方式,顺便讲清楚底层发生了啥。
找第 K 小的数,真就排序完取第 K 个?
先别急着写代码,咱们先想一想:假如你有一个数组 [3, 2, 1, 5, 6, 4],要找第 2 小的数,是不是排序之后变成 [1, 2, 3, 4, 5, 6],然后返回下标为 1 的元素,也就是 2?
这当然可以,但时间复杂度是 O(n log n),其实这个问题没必要排完整个序。
面试官的潜台词往往是:你能不能只排你要的部分?
Python 的 heapq.nsmallest() 是怎么做的?
import heapq
defkth_smallest(nums, k):
return heapq.nsmallest(k, nums)[-1]
这个代码看着简单,它干的事其实是:用一个最大堆(在 nsmallest 的实现里),维护前 k 小的元素,最后返回第 k 个。这样做的时间复杂度是 O(n log k),比起直接排序 O(n log n) 要划算多了,尤其是当 k 很小的时候。
那你要是真想自己写一个,是不是还能用堆?
当然可以!我们可以手动维护一个最大堆(注意:Python 的 heapq 默认是最小堆,所以要反着存)。
来,给个更硬核一点的写法:
import heapq
defkth_smallest(nums, k):
max_heap = [-num for num in nums[:k]]
heapq.heapify(max_heap)
for num in nums[k:]:
if -num > max_heap[0]: # 因为我们是负数,-num > max_heap[0] 就是 num < -max_heap[0]
heapq.heappop(max_heap)
heapq.heappush(max_heap, -num)
return -max_heap[0]
这个写法的好处是你可以跟面试官解释你怎么一步步“手撸了个堆”,显得你真的理解算法。
那有没有更暴力但面试官喜欢的方案?
有,就是 快速选择 QuickSelect。这是快速排序的变种,平均时间复杂度是 O(n)。
import random
defquickselect(nums, k):
ifnot nums:
returnNone
pivot = random.choice(nums)
lows = [el for el in nums if el < pivot]
highs = [el for el in nums if el > pivot]
pivots = [el for el in nums if el == pivot]
if k <= len(lows):
return quickselect(lows, k)
elif k > len(lows) + len(pivots):
return quickselect(highs, k - len(lows) - len(pivots))
else:
return pivots[0]
这个方法没用额外的数据结构,纯靠递归来 partition,够原始,也够优雅。拿出去说也是加分项。
那你问我面试怎么回答?
如果是我被问到这个题,我会这么说:
最优回答:
这个问题我会根据实际需求选择不同的解法:
如果是一次性操作,数据量不大,我可以直接用
heapq.nsmallest()拿出前 K 小的值,取最后一个,代码简单直观,时间复杂度是O(n log k)。但如果我想优化性能,尤其是在大数据场景下,我会考虑用快速选择算法
QuickSelect,它的平均时间复杂度是O(n)。这个方法基于快速排序的分区思想,通过随机选择 pivot 来不断缩小搜索范围,直到找到第 K 小的值。如果数据是动态的,比如数据流中持续加入元素,我可能会维护一个大小为 K 的最大堆,这样每次插入后都能快速判断当前第 K 小的值,这个思路也适用于找第 K 大的元素,只是堆的大小和排序规则要调一下。
所以总结来说,暴力法能做,堆是实用方案,QuickSelect 是性能优选,视场景选择。
你看,这种回答既体现了技术深度,也展示了你的实际思考能力。如果你只会一个库函数,可能就差那么一丢丢了。
也可以看我写的这篇文章《DeepSeek满血复活,直接起飞!》来进行本地搭建。
对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。