窥探算法之美妙——寻找数组中最小的K个数&python中巧用最大堆
原文发表在我的博客主页,转载请注明出处
前言
不论是小算法或者大系统,堆一直是某种场景下程序员比较亲睐的数据结构,而在python中,由于数据结构的极其灵活性,list,tuple, dict在很多情况下可以模拟其他数据结构,Queue库提供了栈和队列,甚至优先队列(和最小堆类似),heapq提供了最小堆,树,链表的指针在python中可以当作最普通的变量,所以python大法好。。。使用python确实可以把程序员从复杂的数据结构中解放开来,重点关注算法。好了言归正传。
题目
前几天看到了一个很经典的算法题目:输入n个整数,找出其中最小的k个数
解决办法
这道题目本身不是很难,而这篇博客更加侧重的是python中的最大堆的使用以及这道题目的解法汇总。
一. 排序
这个思路应该是最简单的,将整个数组排序,然后取出前k个数据就可以了,这个算法的时间复杂度为nlog(n),这里展示快速排序。代码如下:
def partition(alist, start, end):
if end <= start:
return
base = alist[start]
index1, index2 = start, end
while start < end:
while start < end and alist[end] >= base:
end -= 1
alist[start] = alist[end]
while start < end and alist[start] <= base:
start += 1
alist[end] = alist[start]
alist[start] = base
partition(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 None
start = 0
end = length - 1
partition(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:
return
base = alist[start]
index1, index2 = start, end
while start < end:
while start < end and alist[end] >= base:
end -= 1
alist[start] = alist[end]
while start < end and alist[start] <= base:
start += 1
alist[end] = alist[start]
alist[start] = base
return start
def find_least_k_nums(alist, k):
length = len(alist)
#if length == k:
# return alist
if not alist or k <=0 or k > length:
return
start = 0
end = length - 1
index = 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:
return
k = k - 1
for ele in alist:
ele = -ele
if 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)
总结
前面两种方法在数据量较小的时候如果允许改变数组结构可以使用,但是在大数据场景中,同时不改变数组结构,可以使用第三种方法。
窥探算法之美妙——寻找数组中最小的K个数&python中巧用最大堆的更多相关文章
- [算法]找到无序数组中最小的K个数
题目: 给定一个无序的整型数组arr,找到其中最小的k个数. 方法一: 将数组排序,排序后的数组的前k个数就是最小的k个数. 时间复杂度:O(nlogn) 方法二: 时间复杂度:O(nlogk) 维护 ...
- 【算法】数组与矩阵问题——找到无序数组中最小的k个数
/** * 找到无序数组中最小的k个数 时间复杂度O(Nlogk) * 过程: * 1.一直维护一个有k个数的大根堆,这个堆代表目前选出来的k个最小的数 * 在堆里的k个元素中堆顶的元素是最小的k个数 ...
- 求一个数组中最小的K个数
方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如 ...
- 小米笔试题:无序数组中最小的k个数
题目描述 链接:https://www.nowcoder.com/questionTerminal/ec2575fb877d41c9a33d9bab2694ba47?source=relative 来 ...
- 《程序员代码面试指南》第八章 数组和矩阵问题 找到无序数组中最小的k 个数
题目 找到无序数组中最小的k 个数 java代码 package com.lizhouwei.chapter8; /** * @Description: 找到无序数组中最小的k 个数 * @Autho ...
- 求给定数据中最小的K个数
public class MinHeap { /* * * Top K个问题,求给定数据中最小的K个数 * * 最小堆解决:堆顶元素为堆中最大元素 * * * */ private int MAX_D ...
- Java找N个数中最小的K个数,PriorityQueue和Arrays.sort()两种实现方法
最近看到了 java.util.PriorityQueue.刚看到还没什么感觉,今天突然发现他可以用来找N个数中最小的K个数. 假设有如下 10 个整数. 5 2 0 1 4 8 6 9 7 3 怎么 ...
- 求数组中最小的k个数
题目:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. package test; import java.util.Arra ...
- [剑指offer]数组中最小的K个数,C++实现
原创博文,转载请注明出处! http://github.com/wanglei5205 http://cnblogs.com/wanglei5205 # 题目 输入n个整数,找出其中最小的K个数.例如 ...
随机推荐
- hadoop中NameNode、DataNode和Client三者之间协作关系及通信方式介绍
<ignore_js_op> 1)NameNode.DataNode和Client NameNode可以看作是分布式文件系统中的管理者,主要负责管理文件系统的命名空间.集群 ...
- JAVA如何随机生成一个汉字
package com.test; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Rando ...
- C++中不能声明为虚函数的有哪些函数
常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数(非成员函数)只能被overload,不能被o ...
- MySQL数据库学习笔记(六)----MySQL多表查询之外键、表连接、子查询、索引
本章主要内容: 一.外键 二.表连接 三.子查询 四.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复 ...
- IO流的练习 —— 创建用户注册、登陆案例
把上次用集合做的时候的分析拿出来 需求: 用户登录注册案例 按照如下操作,可以让我们更符合面向对象思想: A:这个案例有哪些类 B:每个类中又有哪些东西 C:类与类之间的关系 分析: A:这个案例有哪 ...
- eclipse的使用-------Text File Encoding没有GBK选项的设置
eclipse的使用-------Text File Encoding没有GBK选项的设置 2013-12-25 09:48:06 标签:java myeclipse使用 有一个项目是使用GBK编码的 ...
- 日期选择器:jquery datepicker的使用
helloweba.com 作者:月光光 时间:2012-04-08 21:05 标签: jquery datepicker jquery ui 在jquery ui中,提供了一个非常实用 ...
- AE二次开发技巧之撤销、重做
原文地址:http://www.cnblogs.com/wylaok/articles/2363208.html 可以把AE自带的重做.撤销按钮或工具添加到axToolBarControl上,再把ax ...
- PHP openssl加密扩展使用总结
1.检查服务器是否已安装了openssl组件,没有则先安装好 openssl version [-a] 2.对称加密 查询openssl支持的对称加密算法 openssl_get_cipher_met ...
- DWM 窗体玻璃效果实现
我一直盼望着 Windows 新版本的发布.令人感兴趣的事情莫过于浏览 MSDN® 和 SDK 文档,查找一些可以利用和依赖的最新创新,然后让朋友和同事以及您的老板(如果幸运的话)大开眼界.Windo ...