若干个(大量)数字中找前K大/小的元素--数值型

方法一:根据快速排序划分的思想 :

(1) 递归对所有数据分成[a,b)b(b,d]两个区间,(b,d]区间内的数都是大于[a,b)区间内的数 ;

(2) 对(b,d]重复(1)操作,直到最右边的区间个数小于100个。

注意[a,b)区间不用划分 ;因为[a,b)区间一定小于(b,d]区间;

(3) 返回上一个区间,并返回此区间的数字数目。

如果个数大于100,对(b,d]重复(1)操作,直到最右边的区间个数小于100个;

如果个数小于100,对上一区间的左边进行划分,分为[a2,b2)b2(b2,d2]两个区间,取(b2,d2]区间。

如果个数超过100的就重复1操作,直到最后右边只有100个数为止。 时间复杂度为:O(NlgN)

方法二:维护一个K个元素的堆:

先取出前100个数,维护一个100个数的最小堆,遍历一遍剩余的元素,在此过程中维护堆就可以了。

具体步骤如下:

第一:取前K个元素(例如m=100),建立一个小顶堆。保持一个小顶堆得性质的步骤,运行时间为O(lgK);建立一个小顶堆运行时间为K*O(lgK)=O(KlgK);

第二:顺序读取后续元素,直到结束。每次读取一个元素,如果该元素比堆顶元素小,直接丢弃 ;如果大于堆顶元素,则用该元素替换堆顶元素,然后保持最小堆性质。最坏情况是每次都需要替换掉堆顶的最小元素,因此需要维护堆的代价为(N-K)*O(lgK);

最后这个堆中的元素就是前K最大的K个元素。时间复杂度为O(N lgK)。

方法三:维护一个K个元素的数组:

这种思想类似与思想二,如果在查找比较的时候用二分查找,也可以使时间复杂度变为:O(NlgK)。只不过因为数组时顺序存储,当需要插入更新数据的时候需要移动K个数据,移动的次数变得很多,操作变得复杂。如果是堆,移动的次数最多也是lgK次。所以在这方面堆的效率比数组高。

方法四:分块查找:

如果数据有100W个,求取前100个数据。那么我们可以用分治法的思想,其实对于大量的数据一般都是分治法。大而化小,小而化简,各个击破。最后在组合。因为数据是无限的,而我们的处理资源硬件是有限的,所以必须的分割处理。

方法是:先把100w个数分成100份,每份1w个数。先分别找出每1w个数里面的最大的数,然后比较。找出100个最大的数中的最大的数和最小的数,取最大数的这组的第二大的数,与最小的数比较。如果第二大的数比最小的数大,那么这样就一下砍掉1W个数了;如果第二大的数比最小的数小,那么也可以砍掉9999个数,剩下的肯定不是前100个中的。类似这样可以解决此问题。

时间: 2024-10-08 07:54:59

若干个(大量)数字中找前K大/小的元素--数值型的相关文章

从一个序列中获取前K大的数的一种方法

这个方法是利用快速排序的.在快速排序中,得到中间元素(pivot)之后,比较中间元素之前的元素个数和K的大小关系,从而确定后面该往哪个方向继续递归.如果中间元素前面的元素个数等于K,那就停止递归过程:如果中间元素前面元素个数小于K,那就再中间元素后面进行递归:否则就往中间元素前面进行递归.这样最终得到的是没有排序的前K大的元素,这样再对前K个元素进行一次真正的快速排序.这样就能得到排好序的前K大元素.我随机生成了一个100000个整型数据的文件进行测试,求前10000个元素.这样做用了0.984

无序数组中找第k大的数

类快排算法 由于只要求找出第k大的数,没必要将数组中所有值都排序. 快排中的partition算法,返回key在数组中的位置的cnt(相对于left的偏移量),如果cnt正好等于k,那么问题则得到解决:如果cnt小于k,去左边找第k个:如果cnt>k,则去右边找第k-cnt个.直到key的位置等于k-1,则找对问题的解. /*快排中的划分算法*/ int partition(int* input, int low, int high) { int tmp = input[low]; // 取一个

6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场

题意: 给出一个仙人掌图,然后求他的前K小生成树. 思路: 先给出官方题解 由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉.所以问题就变为有 M 个集合,每个集合里面都有一堆数字,要从每个集合中选择一个恰好一个数加起来.求所有的这样的和中,前 K 大的是哪些.这就是一个经典问题了. 点双联通就不说了 都一眼能看出来做法就是缩点之后每个环每次取一个,然后找最大的k个所以这道题的难点就在这里,做法当然是不知道啦,看了题解和博客才懂的.以前做过两个集合合并的,这个是k个合并,

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3

在N个数中查找前K个最大数

在N个数中查找前K个最大数,主要利用小堆的特点,小堆,是根节点元素小于左右子树元素,查找前K个最大数,先将N个数中的前K个数生成小堆,接着,依次将N中的剩余的数与小堆的根节点相比,如果大于根节点,则根节点换为这个数,再将堆进行生成小堆,依次直到N中无剩余,代码如下 #define N 10000 #define K 100 void Create(int top[],int parent) { int child = 2 * parent + 1; while (child < K) { if

寻找数组中的第K大的元素,多种解法以及分析

遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因为不要求别的信息只要计算出第K大的元素.当然,如果在某种情况下需要频繁访问第K大的元素就可以先进行一次排序在直接得出结果. 第一种方式是这样,用选择排序,冒泡法,或者交换排序这类的排序,对前K个元素进行排序.这三种算法也许不是最快的排序算法.但是都有个性质:计算出最大(小)的元素的算法复杂度是O(N

在未排序的数组中找到第 k 个最大的元素

在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度.思路方法:这道题思路就挺简单的,考查的就是对排序算法的了解.就用排序算法把数组元素按照降序排列,最后返回排序好的数组中下标为k-1的元素即是答

Mysql 查找表中的前n大元素

转载注明出处:http://www.cnblogs.com/liangyongrui/p/8622593.html Mysql 查找表中的前n大元素 用程序写很简单,利用堆维护一下就行了,但是用sql呢? 解法: 假设需要比较的字段是a,找出前n大的行,则答案为count(比a小的行) < n的行.(说起来有点绕..看个例子就懂了) 假设有这样的一个表 Id Name Salary 1 Joe 70000 2 Henry 80000 3 Sam 60000 4 Max 90000 5 Janet

统计前k大的数x

我终于敲上了题目--记起来啦! 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000. 第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000. 第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 //AC自动机x #include<iostream&