问题描述:在N个数中,取M个最大的数。其中N远远大于M。
解决办法:优先队列固然可以,效率不是很高。可以对M个数建一个大顶堆,并用一个变量MIN记录小顶堆的最小值,
* 然后对剩下的N-M个数依次跟MIN比较,如果小于则过,如果大于则替换MIN并且重新构造堆。
* 构堆的时间复杂度是lgM,所以时间复杂度为(N-M)*loM。
JAVA代码:
public class NgetM {
/**
* @param 问题描述:在N个数中,取M个最大的数。其中N远远大于M
* 解决办法:优先队列固然可以,效率不是很高。可以对M个数建一个大顶堆,并用一个变量MIN记录小顶堆的最小值,
* 然后对剩下的N-M个数依次跟MIN比较,如果小于则过,如果大于则替换MIN并且重新构造堆。
* 构堆的时间复杂度是lgM,所以时间复杂度为(N-M)*loM。
*/
public static void main(String[] args) {
int [] N = {10,3,45,56,43,23,12,46,67,87,49,91,32,37,72,61,49,81,85,15,8,36,28,21,55};
int [] M = new int[5];
for(int i =0; i<M.length;i++){
M[i] = N[i];
}
getM(M,N);
display(M);
}
private static void getM(int[] M, int[] N) {
BuildHeap(M);
for(int i=M.length;i<N.length-M.length;i++){
if(N[i] > M[0]){
M[0] = N[i];//替换
BuildHeap(M);
}
}
}
private static void BuildHeap(int[] M) {//构建小顶堆
int lastIndex =M.length-1;
for(int i =(lastIndex-1)/2;i>=0;i--){//从最后一个节点的父节点开始
int k = i;
while(k*2+1<=lastIndex){
int minIndex = 2*k+1;
if(minIndex < lastIndex){
if(M[minIndex] > M[minIndex+1]){//右子数比左子树小
minIndex++;
}
}
if(M[k] > M[minIndex]){
swap(M,k,minIndex);
k=minIndex;
}else{
break;
}
}
}
}
private static void swap(int[] M, int k, int minIndex) {
int temp = M[k];
M[k] = M[minIndex];
M[minIndex] = temp;
}
private static void display(int[] M) {
for(int i =0; i<M.length;i++){
System.out.print(M[i] +" ");
}
}
}