总结 -- 寻找最大的K个数,寻找第K大的数
来源:互联网 发布:js 调用原生手机相册 编辑:程序博客网 时间:2024/06/13 07:44
一、在N个数中,寻找最大的K个数
这里只考虑K不等于1的情况,K = 1时,可以通过N - 1次比较和交换得到结果。
1. N不大的情况下,几千个左右。
① 先排序,快速排序或者堆排序,平均复杂度为O(N*log2N),再取出前K个,O(K)。总时间复杂度,O(N*log2N) + O(K) =O(N*log2N) ;
② 若K <= log2N,可以进行部分排序(选择排序和冒泡排序)。把N个数中的前K个数排序出来,复杂度是O(N*K);
③ 寻找N个数中最大的K个数,本质上就是寻找最大的K个数中最小的那个,也就是第K大的数。然后再遍历一次N个数,计算比第K大的数大的数的个数。
2. N很大的情况下,100亿
① 用容量为K的数组存放数组的前K个数。读入第K+1个数X,扫描数组,找到数组中的最小数Y,比较Y与X,如果X大于Y,用X代替Y。如果X小于等于Y,保持原数组不变。时间负责度O(N*K);
② 进一步,可以用小顶堆来存放着K个数。整个算法的时间负责度为O(Nlog2K);
if(x > h[0]) { h[0] = x; p = 0; while(p < x) { q = 2 * p + 1; if(q >= k) break; if((q < k - 1)&&(h[q + 1] < h[q])) q = q + 1; if(h[q] < h[p]) { t = h[p]; h[p] = h[q]; h[q] = t; p = q; } else break; }}
③ 如果K仍然很大,可以尝试先找到最大的K’个元素,然后找第K’ + 1个到第2 * K’个元素,依次类推。(其中容量K’的堆可以放入内存)。这样,需要扫描所有数据ceil(K/K’)次。
二、在N个数中,寻找第K大的数
1. 可以使用二分策略。对于一个给定的数p,可以在O(N)内找到所有不小于p的数。假如N个数中最大数为Vmax,最小数为Vmin,那么第K大的数一定在区间[Vmax,Vmin]之间。可以在这个区间内二分搜索N个数中的第K大数p。
While(Vmax - Vmin > delta){Vmid = Vmin + (Vmax - Vmin)*0.5;if(f(arr,N,Vmid) >= K)Vmin = Vmid;else Vmax = Vmid; }
f(arr,N,Vmid) 返回数组arr[0,N - 1]中大于等于Vmid的数的个数,delta要比N个数中,任意最小的两个数的差值小。时间复杂度为O(N*log2|Vmax - Vmin|/delta),时间复杂度跟数据分布有关。在数据分布均匀情况下,时间复杂度为O(N*log2N)。
JD 题目1534:数组中第K小的数字
#define Max_N 100005#define Max_M 100005typedef long long LL;using namespace std;int N,M;int A[Max_M];int B[Max_N];LL K;bool judge(LL x){ LL sum = 0; for(int i = 1;i <= M;i++) { LL a = A[i]; sum += upper_bound(B+1 , B+1+N , x - a) - (B+1) ; if(sum >= K) return true; } return sum >= K;}LL solve(){ sort(A + 1,A + 1 + M); sort(B + 1,B + 1 + N); LL min_ = A[1] + B[1]; LL max_ = A[M] + B[N]; LL mid ,ans = 0; while(min_ <= max_) { mid = (min_ + max_)>>1; if(judge(mid)) { ans = mid; max_ = mid - 1; } else min_ = mid + 1; } return ans;}int main(){ while(cin >> M >> N >> K) { for(int i = 1;i <= M;i++) scanf("%d",&A[i]); for(int i = 1;i <= N;i++) scanf("%d",&B[i]); cout << solve() << endl; } return 0;}
2. 如果N个数都是正整数,且它们的取值范围不太大,可以考虑申请空间,记录每个正数出现的次数,然后再从大到小取最大的K个。比如,所有正数在(0,MAXN)之间,利用一个数组count[MAXN]来记录每个正数出现的个数,count[i]表示正数i出现的个数。只要扫描一遍就可以得到count数组,然后寻找第K大的元素。
for(sumCount = 0, v = MAXN - 1;v >= 0;v--) { sumCount += count[v]; if(sumCount >= K) break; } return v;
三、在N个数中,寻找第K到M大的数(0 < K <= M <= N)
先找出第K大p和第M大的数q,再扫描一遍,取出[p ,q]之间的数。
- 总结 -- 寻找最大的K个数,寻找第K大的数
- 【数字之魅】寻找最大的K个数(求第k大的数)
- 寻找最大的第K个数
- 寻找最大的第K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的k个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的K个数
- 寻找最大的k个数
- 寻找最大的K个数
- 命令模式--java
- LinuxCast学习笔记20:Basic_command
- 对象作为函数参数
- 介质恢复与实例恢复
- pefile under python 2.4 (centos os ) EnvironmentError: [Errno 22] Invalid argument
- 总结 -- 寻找最大的K个数,寻找第K大的数
- libnids 中tcp流重组代码
- 努力吧
- C++ 类模板与无类型参数
- 第十五天
- 《自己动手写操作系统》第三章pmtest8源码解析——多任务系统下的地址映射
- Linux设备驱动的分层设计思想(转自宋宝华老师)
- 比赛 I Love This Game
- register_chrdev_region和alloc_chrdev_region