【力扣刷题】剑指 Offer 40. 最小的k个数(大顶堆)

这篇博客介绍了如何在整数数组中找到最小的k个数,提供了三种解题方法:排序法、大顶堆法和快速选择法。排序法直接对数组排序然后取前k个;大顶堆法利用堆的性质,通过存储相反数构建大顶堆,找到最大k个数;快速选择法基于快速排序的思想,通过递归找到最小k个数。文章详细解释了每种方法的思路和操作步骤。
摘要由CSDN通过智能技术生成

题目:

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
输入:arr = [0,1,2,1], k = 1
输出:[0]

解题思路:

解法一:(排序法)时间复杂度O(nlogn)

直接将整个列表排序。最后输出前k个数。

arr.sort()
return arr[:k]

解法二:(大顶堆)

1,特殊情况k=0时直接输出空列表

2,k>0时,先添加k个元素进列表hp(加入的元素放相反数,因为次数要区分的是最大值,而堆默认的是将最小值放在堆顶);然后对将列表hp进行最大顶堆排序(也就是将最大值放在堆顶),然后遍历k+1至len(arr)元素,如果当前元素arr[i]的相反数比堆顶元素大,就将堆顶元素删除,并将当前元素arr[i]的相反数放进堆(排序时已使用heapq堆库,已将列表转化为堆,具有大顶堆的特点,后面使用堆库,都会自动保持大顶堆特点)。最后返回hp列表的相反数即可。

if k==0:
    return []
else:
    hp=[]
    hp=[-i for i in (arr[:k])]  #此时hp仅仅是列表
    heapq.heapify(hp)           #使用堆库,变成了堆
    for i in arr[k:]:
        if -hp[0]>i:
            heapq.heappop(hp)   #删除堆顶那个最大元素
            heapq.heappush(hp,-i)  #将当前元素添加进堆
    ans=[]
    for i in hp:
        ans.append(-i)
    return ans

知识:

1、认识堆

堆也是列表的特殊形式。使用heapq堆库,就能将普通列表转化成堆,后续只要使用堆库添加方式,就是自动选出最小值放在堆顶(堆顶是指的第一个元素)。

注意:堆是默认小顶堆,意思就是堆顶是最小值。

因为此题是要从堆中找出最大值,故取相反数存放,使用堆的小顶堆特点。

2、堆的操作

heapq.heapify(hp)      #将列表hp进行最小值放堆顶操作

heapq.heappop(hp)    #将堆顶元素删除

heapq.headpush(hp, -i)  #将元素-i放进堆hp中,并进行最小值放堆顶操作(每放一个值进去,就会找出最小值放堆顶)

这个和列表hp.append(-i)方式有区别,列表添加元素仅仅放元素进去,但不会找出最小值放堆顶。

解法三:(快排)

具体怎么做就不深究了。

思想是:

1,先选择一个元素当哨兵,然后将整个列表依次与哨兵比较,比哨兵大就放哨兵右边,比哨兵小就放哨兵左边

2,比较一下k与哨兵的索引,如果刚好是k,输出索引0至k-1位置元素;

        如果k小于哨兵索引,则将哨兵左边元素再一次选哨兵分大小,找出最小k个元素(递归)

        如果k大于哨兵索引,则将哨兵右边元素再一次选哨兵分大小,找出最小的k-index(哨兵)-1个最小元素(递归)

学完递归再来实现代码。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值