博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
寻找最大的K个数
阅读量:5263 次
发布时间:2019-06-14

本文共 1304 字,大约阅读时间需要 4 分钟。

前提条件:有N个无序的数,假定它们各不相等,如何选出其中最大的若干个数

解法一:

适用于元素数量不多,内存中可存储整个数组序列。通过快速排序或堆排序对数组排序,时间复杂度为O(N*log2N),然后取出前K个数,时间复杂度为O(K),总时间复杂度为O(N*log2N) + O(K),进一步的,可以知道,我们只需要前 K 大的数,所以并不需要对前 K 个数排序,也不需要对后 N - K 个数排序,这样,通过部分排序的思想,可以选用选择排序,选出前 K 大的值,总时间复杂度为O(N*K),至于选用哪种方式,根据 K 的大小进行选择。

解法二:

适用于元素数量不多,内存中可存储整个数组序列。根据快速排序的思想,每一步中都是将待排序数据分做两组,其中一组数据的任一元素都比另一组数据的任一元素大或者小,因此在本问题中,可以考虑,从数组 S 中随机选出一个元素 X ,把数组分为两部分 Sa 和 Sb,Sa 的元素大于等于 X,Sb的元素小于X。这时,有两种可能性:

  • Sa 中元素的个数小于K,Sa 中所有的数和 Sb 中最大的 K - |Sa| 个元素
  • Sa 中原色的个数大于或等于 K,则需要返回 Sa 中最大的 K 个元素

时间复杂度为O(N*log2K)。

解法三:

适用于元素数量不多,内存中可存储整个数组序列。寻找 N 个数中最大的 K 个数,其实就是要找出 K 个数中最小的那个,那么可以通过二分测探的方式,在这 N 个数所在的区间进行探测。假设 N 个数中最大的是 Vmax,最小的是 Vmin,那么这 N 个数中的第 K 大数就在区间 [Vmin,Vmax]之间,在这个区间二分搜索第 K 大的数。时间复杂度为 O(N*log2N)。

解法四:

 维护一个 K 大小的堆,当前遍历的元素比堆中最小元素大,那么就更新这个堆,最后堆中的 K 个元素就是最大的 K 个数。时间复杂度为O(N*log2K)。这种方法适用于内存无法存储所有的 N 个数。一般情况下,内存中都可以维护一个 K 大小的堆,但是当 K 也特别大,以至于内存中无法存储 K 大小的堆的时候,可以尝试找出 K‘ 个元素,然后再找出 K' + 1 到 2K' 的元素,这样,需要遍历全部元素 K / K’ 趟。

解法五:

如果所有的元素都是正整数,且其范围不大,那么可通过计数排序的思想,来获得前 K 大的值。比如所有整数都在 [0,MAX] 区间,那么通过一个 cnt[MAX] 数组记录元素出现的次数,然后从大到小取出 K 个最大的元素。在实际情况,往往并不能保证所有数都是正整数,且元素都是小范围,那么当元素有正有负,其其范围涵盖较广的情况,可以将元素所在区间 [Vmin,Vmax] 分成M块,每个小区间跨度在 (Vmax - Vmin)/ M,统计各个小区间内元素的个数,可知前 K 大的数在哪个区间,然后再对那个区间进行处理,对小区间处理方式就可参考前面所述的几种方法了。

写在最后

以上参考自 《编程之美》

 

转载于:https://www.cnblogs.com/ZhaoxiCheung/p/8674327.html

你可能感兴趣的文章
JUnit
查看>>
WPF文本框只允许输入数字[转]
查看>>
事务的四种隔离级别和七种传播行为
查看>>
dom4j 通用解析器,解析成List<Map<String,Object>>
查看>>
Denver Broncos nfl jersey authentic considering alot more
查看>>
HDU 3572 最大流
查看>>
Bootstrap基础
查看>>
Javascript: 从prototype漫谈到继承(1)
查看>>
POJ 3974 Palindrome | 马拉车模板
查看>>
oracle表关联update和表建立索引
查看>>
JVM运行内存分类
查看>>
【学习】博弈相关:Nim
查看>>
BZOJ4552 HEOI/TJOI2016 排序 线段树、二分答案
查看>>
13. 用Roberts、Sobel、Prewitt和Laplace算子对一幅灰度图像进行边缘检测。观察异同。...
查看>>
Web 安全入门-书籍及建议
查看>>
prim算法基础详解(无向赋权图的最小生成树MST)
查看>>
vijos1404 遭遇战
查看>>
Androidstudio创建项目jdk版本问题
查看>>
WCF 第五章 行为 实现事务(操作行为)
查看>>
WCF 第七章 寄宿 在一个IIS寄宿服务中开启ASMX特性
查看>>