剑指 Offer 40. 最小的k个数
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 40. 最小的k个数相关的知识,希望对你有一定的参考价值。
剑指 Offer 40. 最小的k个数
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
排序
本题使用排序算法解决最直观,对数组 arr 执行排序,再返回前 k 个元素即可。使用任意排序算法皆可,本文采用并介绍 快速排序 ,为下文 方法二 做铺垫。
快速排序原理:
- 快速排序算法有两个核心点,分别为 “哨兵划分” 和 “递归” 。
- 哨兵划分操作: 以数组某个元素(一般选取首元素)为 基准数 ,将所有小于基准数的元素移动至其左边,大于基准数的元素移动至其右边。
如下图所示,为哨兵划分操作流程。通过一轮 哨兵划分 ,可将数组排序问题拆分为 两个较短数组的排序问题 (本文称之为左(右)子数组)。
递归: 对 左子数组 和 右子数组 递归执行 哨兵划分,直至子数组长度为 1 时终止递归,即可完成对整个数组的排序。
如下图所示,为示例数组 [2,4,1,0,3,5] 的快速排序流程。观察发现,快速排序和 二分法 的原理类似,都是以 log \\log log 时间复杂度实现搜索区间缩小。
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
def quick_sort(arr, l, r):
# 子数组长度为 1 时终止递归
if l >= r:
return
# 哨兵划分操作(以 arr[l] 作为基准数
i, j = l, r
while i < j:
while i <j and arr[j] >= arr[l]:
j-=1
while i <j and arr[i] <= arr[l]:
i +=1
arr[i], arr[j] = arr[j], arr[i] # arr[j] < arr[l] <arr[i]时候
arr[l], arr[i] = arr[i], arr[l] # 交换哨兵
# 递归左(右)子数组执行哨兵划分
quick_sort(arr,l,i-1)
quick_sort(arr,i+1,r)
quick_sort(arr, 0, len(arr)-1)
return arr[:k]
基于快速排序的数组划分
题目只要求返回最小的 k 个数,对这 k 个数的顺序并没有要求。因此,只需要将数组划分为 最小的 k 个数 和 其他数字 两部分即可,而快速排序的哨兵划分可完成此目标。
根据快速排序原理,如果某次哨兵划分后 基准数正好是第 k + 1 k+1 k+1 小的数字 ,那么此时基准数左边的所有数字便是题目所求的 最小的 k k k 个数 。
根据此思路,考虑在每次哨兵划分后,判断基准数在数组中的索引是否等于
k
k
k ,若 true
则直接返回此时数组的前 k
个数字即可。
算法流程:
getLeastNumbers()
函数:
- 若 k k k 大于数组长度,则直接返回整个数组;
- 执行并返回 quick_sort() 即可;
quick_sort()
函数:
注意,此时 quick_sort()
的功能不是排序整个数组,而是搜索并返回最小的
k
k
k 个数。
- 哨兵划分:
- 划分完毕后,基准数为
arr[i]
,左 / 右子数组区间分别为[l,i−1] , [i + 1, r]
;
- 递归或返回:
- 若 k < i k < i k<i ,代表第 k + 1 k + 1 k+1 小的数字在 左子数组 中,则递归左子数组;
- 若 k > i k > i k>i ,代表第 k + 1 k + 1 k+1小的数字在 右子数组 中,则递归右子数组;
- 若 k = i k = i k=i,代表此时 a r r [ k ] arr[k] arr[k] 即为第 k + 1 k + 1 k+1 小的数字,则直接返回数组前 k k k 个数字即可;
class Solution(object):
def getLeastNumbers(self, arr, k):
"""
:type arr: List[int]
:type k: int
:rtype: List[int]
"""
if k >= len(arr):
return arr
def quick_sort(l, r):
i , j =l,r
while i <j:
while i <j and arr[j] >= arr[l]:
j-=1
while i <j and arr[i] <= arr[l]:
i +=1
arr[i], arr[j] = arr[j], arr[i]
arr[l], arr[i] = arr[i], arr[l]
# i 为哨兵的索引
if k < i: return quick_sort(l, i - 1)
if k > i: return quick_sort(i + 1, r)
return arr[:k]
return quick_sort(0, len(arr) - 1)
参考
以上是关于剑指 Offer 40. 最小的k个数的主要内容,如果未能解决你的问题,请参考以下文章