`
gaofen100
  • 浏览: 1227857 次
文章分类
社区版块
存档分类
最新评论

找出第k大的数

 
阅读更多

问题:

从一个数组里面,找出第K大的数。

题目很简单,要想把第K个数找出来,其实也挺容易的。

第一种方法:无非就是先排序,比如用Merge Sort算法,整个算法复杂度为 O(NlgN), 然后找到第K个即可。

第二种方法:如果k很小,比如第五个最大的数,而整个数组的长度非常的大,那么,还有一种方法就是,我做k遍找最大的数,每做一遍,就把最大的放在数组的最后面,然后减少数组扫描的范围,就可以把第k大的数找出来,这样做的复杂度就是O(K*N),在K很小的情况下,还是不错的。

第三种方法:我们可以借助quicksort的思想,把数组的值分成两部分,一部分比那个pivot大,一部分比pivot小,因为我们知道pivot在数组中的位置,所以比较k和pivot的位置就知道第k大的值在哪个范围,我们不断的进行recursion, 直到pivot就是第K大的值。时间复杂度,出乎意料,为O(N),但是这是平均复杂度。 为何它的平均复杂度比quicksort的复杂度低呢?重要原因是quicksort要对pivot两边的子数组还要排序,而我们其实只需要对其中一个进行处理,所以复杂度更低。具体怎么推导,请参考算法导论。

但是本文讲的是另一个算法,叫做SELECT 算法,它能在时间复杂度为O(N)的情况下找出第K大的数。先把算法贴出来,然后再讲。


第一步:把数组分成\lfloor n/5 \rfool 这么多子数组,每个子数组里包含5个数,因为会有无法整出的可能,所以最后一个子数组会小于5.

第二步:用insertion sorting 把这5个数排序,然后找出中位数,也就是第3个。

第三步:把获得的中位数又排序,找出中位数的中位数。如果中位数的个数是偶数,那么取排好序的第 m/2 个数,m指的是中位数的个数。

第四步:然后呢,把原来的数组分成两个部分,一部分比那个“中位数的中位数”大,一部分比那个“中位数的中位数”小。我们可以假设左边的数大,右边的数小。然后我们可以得到“中位数的中位数”的位置i.

第五步:如果i = k, 那么那个“中位数的中位数”就是第k大的数。如果 i < k, 不用说,第k大的在“中位数的中位数”的右边,否则就在左边。我们一直recursely 这么做,那么就一定能够找到第K大的值了。

其实,算法还是比较容易懂得,关键的关键,是复杂度的分析。如果能够知道复杂度如何求出来的,那么,对算法本身就了解得更清楚。


要讲复杂度,首先看一个图。


图中的X 就是“中位数的中位数”, 而且箭头的方向是从大数指到小数。所以,我们可以知道,至少灰色区域的都比X大,这是整个复杂度分析的关键,而,其它点能否说它比X大,我们不能保证。而灰色区域里最多有多少个数呢?因为X是中位数的中位数,所以,比X大的中位数最少有 [(\lfloor n/5 \rfool) * (1/2) - 2] 个(这个值也是关键), 这里减2是因为要去除X本身,第二呢,还要去除一个中位数---这个中位数所在的子数组个数小于5. 所以,最坏最坏的情况,第K大的值不在灰色区域里,那么我们就要对剩下部分进行不断的SELECT。剩余部分就是n - 3[(\lfloor n/5 \rfool) * (1/2) - 2] = O(7n/10) .

整个过程中,第1,2,4步所需时间为O(n), 注意第2步的复杂度不为O(n^2),第3步的复杂度为 T(n/5),第五步的复杂度为 T(7n/10)。

所以,复杂度的递归公式为: T(n) =T(n/5) +T(7n/10) + O(n), 算出来以后T(n) =O(n).





分享到:
评论

相关推荐

    找第k小的数

    本文件给出了一种不同角度的在一个数组中找第k小的数,特别是在大型数据里有较快的速度(本算法给出的是20个数)。

    N个数求第K大

    c语言求N个数中第K大的值,采用改进型快排

    17082 两个有序数序列中找第k小

    现在请你用分治算法 找出X和Y的第k小的数 算法时间复杂度为O max{logm logn} 此题请勿采用将序列X和Y合并找第k小的O m+n 的一般方法 要充分利用X和Y已经排好序的这一特性 输入格式 第一行有三个数 分别是...

    典型的Top K算法 找出一个数组里面前K个最大数.doc

    典型的Top K算法 找出一个数组里面前K个最大数 Top K算法是解决一个经典的问题,即在一个大规模的数组中找到前K个最大数的问题。在这个问题中,我们需要在一个数组中找到前K个最大数,例如在搜索引擎中,需要找出最...

    算法:求第k小元素

    首先,取数组的第一个、最后一个和中间元素,找出三个中最小的作为新的枢轴,然后根据枢轴的位置将数组分为三部分:小于枢轴、等于枢轴和大于枢轴。如果k在小于枢轴的区间,就在这个区间重复此过程;如果k在大于枢轴...

    C语言TOP-K问题(从一堆数据中找出最大的k个数或者最小的k个数)

    在C语言中,处理大数据集并找出其中最大的k个数或最小的k个数是一个常见的问题,这通常涉及到数据结构中的“堆”概念。堆是一种特殊的树形数据结构,满足以下性质:每个父节点的值要么大于等于其子节点(大顶堆),...

    链表查找倒数第K个数

    链表功能的一个扩展延伸,查找倒数第K个元素,是某年考研题

    删数问题给定n 位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个

    对于给定的n位正整数a 和正整数k,设计一个算法找出剩下数字组成的新数 最小的删数方案。 «编程任务: 对于给定的正整数a,编程计算删去k个数字后得到的最小数。 Input 由文件input.txt提供输入数据。文件的第1...

    求第K大元素

    这个问题的基本目标是从一个数组或集合中找出第K个最大的元素,其中K通常是一个正整数,且K小于等于数组的元素个数。这个任务不仅涉及到排序,还涉及到效率和时间复杂度的优化,因为对于大数据集,快速找到第K大元素...

    两个有序数序列中找第k小

    现在请你用分治算法,找出X和Y的第k小的数,算法时间复杂度为O(max{logm, logn})。 此题请勿采用将序列X和Y合并找第k小的O(m+n)的一般方法,要充分利用X和Y已经排好序的这一特性。 输入格式 第一行有三个数,...

    php-leetcode题解之找出第K大的异或坐标值.zip

    在本压缩包中,我们关注的是一个PHP编程与LeetCode算法题目的结合——"找出第K大的异或坐标值"。这是一道涉及到数组处理、位运算和排序的经典算法问题,对于提升PHP开发者在算法和数据结构上的能力具有重要意义。 ...

    两个有序数序列中找第k小(必做)

    已知两个已经排好序(非减序)的序列X和Y,其中X的长度为m,Y长度为n, 现在请你用分治算法,找出X和Y的第k小的数,算法时间复杂度为O(max{logm, logn})。

    选择第k小问题.zip

    这个问题要求在一组无序的元素中找到第k小(或第k大)的元素,而不必对整个序列进行完全排序。在本案例中,我们关注的是如何使用分治策略来解决这个问题,并通过Python 3.7实现。 分治法是一种重要的算法设计策略,...

    用效率比较高的算法寻找K个最大的数

    用最优的算法,寻找到一个序列之中的K各最大的数

    在一堆数中取得前K个最大最小的数的方法

    - **求解不同的浮点数**:在面对需要找出N个数中最大的K个不同浮点数的问题时,上述方法同样适用,但需要注意浮点数的比较方式以及哈希键的设计方法。 - **求解第k到第m大的数**:可以将问题转化为求解m-k+1个第k...

    求解第K小元素,找中位数

    找中值和第k小元素,找出A[1...N]中第k小元素.找第K小元素 需要找中位数: 如果有偶数个,则找第n/2或n/2+1个小元素则可找到中位数; 如果有奇数个,则找第n/2+1个小元素则可找到中位数。

    算法/编程练习:找出若干个数使其和最接近于M

    找出若干个数使其和最接近于M 1. 题目 给定一个由正数组成的列表alts,一个目标数M 需要从alts中选取若干个备选数,使其和为M 若找不到和刚好与M相等的备选数列表,则返回和与M最接近的备选数列表 若有多个结果,...

    求数列中的第1~k小元素

    设计算法实现在一个具有在n各互不相同元素的数组A[1…n]中找出所有前k个最小元素的问题,这里k不是常量,即它是输入数据的一部分。要求算法的时间复杂性为Θ(n)。 2. 具体要求 输入的第一行是一个正整数m,表示测试...

    找出n以内最大的k个素数c.pdf

    以下,我们将结合C语言,深入探讨如何利用筛选法找出n以内最大的k个素数。 在开始之前,我们首先明确一下筛选法的基本原理。筛选法的核心思想在于首先假设所有的数都是素数,然后按照素数的定义,逐步排除所有非...

Global site tag (gtag.js) - Google Analytics