问题描述:有 N (N>1000000)个数,求出其中的前K个最小的数(又被称作topK问题)。

这类问题似乎是备受面试官的青睐,相信面试过互联网公司的同学都会遇到这来问题。下面由浅入深,分析一下这类问题。

思路1:最基本的思路,将N个数进行完全排序,从中选出排在前K的元素即为所求。有了这个思路,我们可以选择相应的排序算法进行处理,目前来看快速排序,堆排序和归并排序都能达到O(NlogN)的时间复杂度。当然,这样的答案也是无缘offer的。

思路2:可以采用数据池的思想,选择其中前K个数作为数据池,后面的N-K个数与这K个数进行比较,若小于其中的任何一个数,则进行替换。这种思路的算法复杂度是O(N*K),当答出这种算法时,似乎离offer很近了。

有没有算法复杂度更低的方法呢?

从思路2可以想到,剩余的N-K个数与前面K个数比较的时候,是顺序比较的,算法复杂度是K。怎么在这方面做文章呢? 采用的数据结构是堆。

思路3:大根堆维护一个大小为K的数组,目前该大根堆中的元素是排名前K的数,其中根是最大的数。此后,每次从原数组中取一个元素与根进行比较,如小于根的元素,则将根元素替换并进行堆调整(下沉),即保证大根堆中的元素仍然是排名前K的数,且根元素仍然最大;否则不予处理,取下一个数组元素继续该过程。该算法的时间复杂度是O(N*logK),一般来说企业中都采用该策略处理topK问题,因为该算法不需要一次将原数组中的内容全部加载到内存中,而这正是海量数据处理必然会面临的一个关卡。如果能写出代码,offer基本搞定。

还有没有更简单的算法呢?答案是肯定的。

思路4:利用快速排序的分划函数找到分划位置K,则其前面的内容即为所求。该算法是一种非常有效的处理方式,时间复杂度是O(N)(证明可以参考算法导论书籍)。对于能一次加载到内存中的数组,该策略非常优秀。如果能完整写出代码,那么相信面试官会对你刮目相看的。

下面,给出思路4的Python代码:

def partition(data,start,end):
if len(data)==1:
return 0
small=start
p=small+1
while p<=end:
if data[p]<data[start]:
small+=1
data[p],data[small]=data[small],data[p]
p+=1
data[start],data[small]=data[small],data[start]
return small def topk(data,k):
if k==0:
return None
if len(data)<=k:
return data
left=0
right=len(data)-1
s=partition(data,left,right)
while s+1!=k: #下标加1才能与前k的k进行比较
if s+1>k:
right=s-1
if s+1<k:
left=s+1
s=partition(data,left,right) return data[:k]
 

排序中topK那点事(转)的更多相关文章

  1. 开发中关于Git那些事

    如果你想精通Git,直接到 Git官网 把这本ProGit掌握已足以Pro Git 此文主要介绍一切开发中常用的git命令和一些配置技巧(诸如git别名配置,log打印技巧,版本回退以及分支管理等). ...

  2. 开发中关于Git那些事(续:Git变基)

    其实上一篇写的内容仅仅是Git的冰山一角,如果你认为Git就是简简单单的几行命令,那只能说明你还没有真正了解Git这个强大的内容寻址文件系统.这篇文章,还是接着介绍一些实用但是很少有人知晓的一些命令, ...

  3. 8、sort排序中比较函数的几种应用方式

    1.待排序中的元素作数组的下标或map的键值 例题:PAT甲级_1141 PAT Ranking of Institutions #include<bits/stdc++.h> using ...

  4. 深度学习在美团点评推荐平台排序中的应用&& wide&&deep推荐系统模型--学习笔记

    写在前面:据说下周就要xxxxxxxx, 吓得本宝宝赶紧找些广告的东西看看 gbdt+lr的模型之前是知道怎么搞的,dnn+lr的模型也是知道的,但是都没有试验过 深度学习在美团点评推荐平台排序中的运 ...

  5. 探讨 JS 的面向对象中继承的那些事

    最近学了 JS 的面向对象,这篇文章主要是探讨 JS 的面向对象中继承的那些事. JS中继承的特点: 1.子类继承父类: 2.子类可以用父类的方法和属性 3.子类的改变可以不影响父类 下面用一个例子来 ...

  6. django基础之day09,Forms组件在程序中做了哪些事? 校验数据、渲染标签、展示信息

    ******************************* Forms组件 *************************************************** Forms组件在 ...

  7. 「译」forEach循环中你不知道的3件事

    前言 本文925字,阅读大约需要7分钟. 总括: forEach循环中你不知道的3件事. 原文地址:3 things you didn't know about the forEach loop in ...

  8. Hadoop经典案例(排序&Join&topk&小文件合并)

    ①自定义按某列排序,二次排序 writablecomparable中的compareto方法 ②topk a利用treemap,缺点:map中的key不允许重复:https://blog.csdn.n ...

  9. leetcode347 —— n中topK && PriorityQueue(Heap) && Map遍历

    题目要求:求前K个最频繁出现的数字. 1.很容易想到,使用HashMap<Integer,Integer>来存储<number,frequency>键值对 1 int n = ...

随机推荐

  1. TCP/IP三次握手与四次握手

    原文地址 http://blog.csdn.net/whuslei/article/details/6667471 http://blog.csdn.net/wo2niliye/article/det ...

  2. 【ADO.NET】SqlBulkCopy批量添加DataTable

    使用事务和SqlBulkCopy批量插入数据 SqlBulkCopy是.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其他数据源的数据 ...

  3. BZOJ 1263 整数划分(数学+高精度)

    我们不妨考虑可以划分为实数的情况,设划分为x份实数,使得总乘积最大. 易得当每一份都相等时乘积最大.即 ans=(n/x)^x. 现在只需要求出这个函数取得最大值的时候x的取值了. 两边取对数,则有l ...

  4. Python 配置日志的几种方式

    Python配置日志的几种方式 作为开发者,我们可以通过以下3种方式来配置logging: (1)使用Python代码显式的创建loggers,handlers和formatters并分别调用它们的配 ...

  5. BZOJ4735 你的生命已如风中残烛(组合数学)

    将每个位置上的数都-1,则显然相当于前缀和始终非负. 然后就是完全想不到的了.考虑往里面加一张-1的牌.假设在一个合法排列的最后添上一个-1,那么在该排列的所有循环同构排列中,满足前m个前缀和都非负的 ...

  6. Greenlet-手动切换

    yield()是自己写的协程,Greenlet( )是已经封装好了的协程. 协程:遇到 I/O 操作就切换到别的地方了(先去处理其他携程去了).等原协程的 I/O 操作一完成就切回去.这样就把 I/O ...

  7. Give NetScaler a “Tune-Up”

    Give NetScaler a “Tune-Up” https://www.citrix.com/blogs/2014/10/21/give-netscaler-a-tune-up/ To Opti ...

  8. BZOJ3526 [Poi2014]Card 【线段树】

    题目链接 BZOJ3526 题解 思来想去,发现很显然可以用线段树维护 每个区间保存所有合法方案的左右端点[当左端点一定是,右端点当然存最小的那个就行了] 这么整的数,\(\frac{1}{1000} ...

  9. UVA.839 Not so Mobile ( 二叉树 DFS)

    UVA.839 Not so Mobile ( 二叉树 DFS) 题意分析 给出一份天平,判断天平是否平衡. 一开始使用的是保存每个节点,节点存储着两边的质量和距离,但是一直是Runtime erro ...

  10. AOJ.667 抢占白房子

    抢占白房子 点我挑战题目 考察点 字符串 Time Mem Len Lang 14ms 444 KB 0.75 K GCC 题意分析 数据仅有一组,根据题目,左上角的一个格子为白色,与白色相邻的(无论 ...