无序整数数组查找第k个最大的数
速览
对于无序整数数组查找第k个最大的数,主要分为如下两种情况
- 内存足够
- 快排
- 二分
- 按数值区间二分
- 按位二分
- 内存不足
- 堆排序(维护一个堆)
- 数据范围取值不大
- 键值索引
算法详解
内存足够
快排
算法思想
避免对所有数进行排序,采用快速排序分堆,并递归其中一半,直到所有<val[pivot]的数量为k
伪代码
int quickSort(int[]& num,int _begin,int _end){int i=_begin,j=_end;int pivot=num[0];while(i<j){while(i<j && num[j]<=pivot) j--;while(i<j && num[i]>pivot) i++;swap(num[i],num[j]);}swap(num[0],num[i]);return i+1;}int FindKth(int[]& num,int k){int n=num.size();int curIdx=0;int l=0,r=n-1;while(curIdx!=k){curIdx=quickSort(num,l,r);if(curIdx<k){l=curIdx+1;}else if(curIdx>k){r=curIdx-1;}}return num[k-1];}
二分
划定中值区域,以二分法来找到第k个数所在的数值区间。
按数值区间二分
假设N个数的范围为[max_val,min_val],则第k个大的数一定在此区间
/* 伪代码 */while(max_val-min_val>delta){mid_val=min_val+(max_val-min_val)>>1;if(count(num,mid_val)>k)/* count() 返回num中>=mid_val的数量 */min_val=mid_val;elsemax_val=mid_val;}/* 时间复杂度 */ O(N*log(N))
按位二分
假设元素范围均在,则由高位往地位比较,按1、0来分为两个部分,若1区间中整数个数
cnt_1>=k,则在该区间中继续寻找第k大的数;否则在0区间中寻找第k=k-cnt_1个大的数。
内存不足
上述方法都需要将整个数组遍历一遍,当N非常大时(100亿),上述算法就适用了,故可采用数据结构——小根堆(C++中为优先队列),来解决上述问题。
