原文发表在我的博客主页,转载请注明出处

前言

不论是小算法或者大系统,堆一直是某种场景下程序员比较亲睐的数据结构,而在python中,由于数据结构的极其灵活性,list,tuple, dict在很多情况下可以模拟其他数据结构,Queue库提供了栈和队列,甚至优先队列(和最小堆类似),heapq提供了最小堆,树,链表的指针在python中可以当作最普通的变量,所以python大法好。。。使用python确实可以把程序员从复杂的数据结构中解放开来,重点关注算法。好了言归正传。

题目

前几天看到了一个很经典的算法题目:输入n个整数,找出其中最小的k个数

解决办法

这道题目本身不是很难,而这篇博客更加侧重的是python中的最大堆的使用以及这道题目的解法汇总。

一. 排序

这个思路应该是最简单的,将整个数组排序,然后取出前k个数据就可以了,这个算法的时间复杂度为nlog(n),这里展示快速排序。代码如下:

def partition(alist, start, end):if end <= start:returnbase = alist[start]index1, index2 = start, endwhile start < end:while start < end and alist[end] >= base:end -= 1alist[start] = alist[end]while start < end and alist[start] <= base:start += 1alist[end] = alist[start]alist[start] = basepartition(alist, index1, start - 1)partition(alist, start + 1, index2)def find_least_k_nums(alist, k):length = len(alist)if not alist or k <=0 or k > length:return Nonestart = 0end = length - 1partition(alist, start, end)return alist[:k]if __name__ == "__main__":l = [1, 9, 2, 4, 7, 6, 3]min_k = find_least_k_nums(l, 7)print min_k

二. 快速排序的思想

这种解法是在第一种解法上面的一种改进,快速排序的思想大家都已经知道,现在我们只需要最小的k个数,所以如果我们在某次快速排序中,选择的基准树的大小刚好是整个数组的第k小的数据,那么在这次排序完成之后,这个基准数之前的数据就是我们需要的(尽管他们并不是有序的),这个方法同样改变了数组,但是可以将时间复杂度压缩到O(n),话不多说,直接上代码:

def partition(alist, start, end):if end <= start:returnbase = alist[start]index1, index2 = start, endwhile start < end:while start < end and alist[end] >= base:end -= 1alist[start] = alist[end]while start < end and alist[start] <= base:start += 1alist[end] = alist[start]alist[start] = basereturn startdef find_least_k_nums(alist, k):length = len(alist)#if length == k:#    return alistif not alist or k <=0 or k > length:returnstart = 0end = length - 1index = partition(alist, start, end)while index != k:if index > k:index = partition(alist, start, index - 1)elif index < k:index = partition(alist, index + 1, end)return alist[:k]if __name__ == "__main__":l = [1, 9, 2, 4, 7, 6, 3]min_k = find_least_k_nums(l, 6)print min_k

三. 最大堆

上面方法虽然要改变数组的结构,在不要求数字顺序的情况下使用可以获得很好的时间复杂度,但是假如数字非常的多,一次性将其载入内存变得不可能或者内存消耗过大,那上面的方法就不再可行,我们可以创建一个大小为K的数据容器来存储最小的K个数,然后遍历整个数组,将每个数字和容器中的最大数进行比较,如果这个数大于容器中的最大值,则继续遍历,否则用这个数字替换掉容器中的最大值。这个方法的理解也十分简单,至于容器的选择,很多人第一反应便是最大堆,但是python中最大堆如何实现呢?我们可以借助实现了最小堆的heapq库,因为在一个数组中,每个数取反,则最大数变成了最小数,整个数字的顺序发生了变化,所以可以给数组的每个数字取反,然后借助最小堆,最后返回结果的时候再取反就可以了,代码如下:

import heapq
def get_least_numbers_big_data(self, alist, k):max_heap = []length = len(alist)if not alist or k <= 0 or k > length:returnk = k - 1for ele in alist:ele = -eleif len(max_heap) <= k:heapq.heappush(max_heap, ele)else:heapq.heappushpop(max_heap, ele)return map(lambda x:-x, max_heap)if __name__ == "__main__":l = [1, 9, 2, 4, 7, 6, 3]min_k = get_least_numbers_big_data(l, 3)

总结

前面两种方法在数据量较小的时候如果允许改变数组结构可以使用,但是在大数据场景中,同时不改变数组结构,可以使用第三种方法。

转载于:https://www.cnblogs.com/cotyb/p/5205123.html

窥探算法之美妙——寻找数组中最小的K个数python中巧用最大堆相关推荐

  1. 寻找数组中最小的k个数(快排和堆排)

    题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 思路1:利用快排的思想,寻找第k个位置上正确的数,k位置前面的数即 ...

  2. 【算法】数组与矩阵问题——找到无序数组中最小的k个数

    1 /** 2 * 找到无序数组中最小的k个数 时间复杂度O(Nlogk) 3 * 过程: 4 * 1.一直维护一个有k个数的大根堆,这个堆代表目前选出来的k个最小的数 5 * 在堆里的k个元素中堆顶 ...

  3. 找出无序数组中最小的k个数(top k问题)

    2019独角兽企业重金招聘Python工程师标准>>> 给定一个无序的整型数组arr,找到其中最小的k个数 该题是互联网面试中十分高频的一道题,如果用普通的排序算法,排序之后自然可以 ...

  4. 小米笔试题:无序数组中最小的k个数

    题目描述 链接:https://www.nowcoder.com/questionTerminal/ec2575fb877d41c9a33d9bab2694ba47?source=relative 来 ...

  5. 用大顶堆取出一个数组中最小的k个数

    eg:从一亿个数中取出最小的k个数字 分析: 大顶堆满足,当前元素永远大于他的左右子树的值,非叶子节点的下标为n/2-1,左子树下标为i*2+1右子树下标为i*2+2 源码: import java. ...

  6. 【算法】剑指 Offer 40. 最小的k个数 【重刷】

    1.概述 输入整数数组 arr ,找出其中最小的 k 个数.例如,输入4.5.1.6.2.7.3.8这8个数字,则最小的4个数字是1.2.3.4. 示例 1: 输入:arr = [3,2,1], k ...

  7. 剑指offer 40.最小的 K 个数 python代码

    题目 寻找数组中的最小的k个数,也叫topk问题. 牛客网测试地址 注意: 牛客网的提交需要将最终的结果排序 思路 快速排序的 partition() 方法,会返回一个整数 j 使得 a[l-j-1] ...

  8. c语言从4个整数中找最小的数,编程之法:面试和算法心得(寻找最小的k个数)...

    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入n个整数,输出其中最小的k个. 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个 ...

  9. 程序员编程艺术:第三章、寻找最小的k个数

    程序员编程艺术:第三章.寻找最小的k个数 作者:July. 时间:二零一一年四月二十八日. 致谢:litaoye, strugglever,yansha,luuillu,Sorehead,及狂想曲创作 ...

最新文章

  1. 《跟菜鸟学Cisco UC部署实战》-第 1 章 规划-课件(一共12章,免费)
  2. 三星的 Logo 原来是这么来哦! | 每日趣闻
  3. html footer 布局,详解CSS经典布局之Sticky footer布局
  4. 一个经典的字母排列算法
  5. Class类是什么? Class.forName()是干什么的?
  6. unity3d优化总结篇
  7. BZOJ2081 [Poi2010]Beads
  8. [转]项目方面的做人处事
  9. iPhone 12全球销量超过1亿部 研究机构称在4月份就已超过
  10. 响应式Web设计的9项基本原则
  11. ╭☆难以割舍^_^就是牵挂☆╮
  12. 差分约束——vijos1589
  13. 【软件测试】软件测试过程模型
  14. CSTSOFT ActiveX GDIPlus Pack 2021.03
  15. 好书推荐:道德经说什么
  16. 中小学计算机培训心得体会,中小学计算机管理员培训心得体会材料
  17. (glidejs)glidejs的使用
  18. sqlserver字符串转日期
  19. 阿里总部对外解密双11超级工程背后的数据库技术
  20. for循环-结束循环

热门文章

  1. C语言头文件一般以什么名称结尾,c语言书写规范.doc
  2. java elasticsearch_在Spring java框架中使用ElasticSearch的最佳方式
  3. json在java中的使用_在Java中使用JSON
  4. php 自动处理小图的代码,php对图像的各种处理函数代码小结
  5. mongodb连接池 php,node.js,mongodb_nodejs使用mongodb连接池,node.js,mongodb - phpStudy
  6. 计算机硬盘中没有什么 a文件夹,为什么硬盘上没有A和B盘?
  7. java 视频 缩略图_java获取视频缩略图
  8. 使用argparse解析命令行参数
  9. 利用Future异步获取多线程的返回结果
  10. 学习Linux第一天