题目描述
现有一些随机生成的数字要将其依次传入,请设计一个高效算法,对于每次传入一个数字后,算出当前所有传入数字的中位数。(若传入了偶数个数字则令中位数为第n/2小的数字,n为已传入数字个数)。
给定一个int数组A,为传入的数字序列,同时给定序列大小n,请返回一个int数组,代表每次传入后的中位数。保证n小于等于1000。
测试样例:
[1,2,3,4,5,6],6
返回:[1,1,2,2,3,3]
核心思路:
1.维护一个大顶堆,一个小顶堆,且保证两点:
1)小顶堆里的全大于 大顶堆里的;
2)2个堆个数的差值小于等于1
2.当insert的数字个数为奇数时:使小顶堆个数比大顶堆多1;
当insert的数字个数为偶数时,使大顶堆个数跟小顶堆个数一样。
3.那么当总数字个数为奇数时,中位数就是小顶堆堆头;
当总数字个数为偶数时,中位数就是 2个堆堆头平均数
与剑指offer中的数据流中的中位数 题目一样。
注意,当最大堆与最小堆的元素个数相同时,因为最大堆中放的是小元素,所以这次中位数result结果为它。
又要注意,因为第一次的元素最终放入最小堆,然后两个堆依次加元素。所以最大堆的元素个数只可能小于或等于最小堆的元素个数。
当最大堆的个数比最小堆要小的时候,这个时候中位数result应该取最小堆中的元素。
import java.util.*;
public class Middle {
public int[] getMiddle(int[] A, int n) {
// write code here
PriorityQueue<Integer>max = new PriorityQueue<>(15,new Comparator<Integer>() {
public int compare(Integer integer1,Integer integer2){
return integer2.compareTo(integer1);
}
});
PriorityQueue<Integer>min =new PriorityQueue<>();
int result[] = new int[n];
for (int i = 0; i < result.length; i++) {
if(i%2==1){//有偶数个
min.offer(A[i]);
max.offer(min.poll());
}else {
max.offer(A[i]);
min.offer(max.poll());
}
//如果个数为奇数(i%2==0),取最大堆的,因为最大堆的是较小值
if(!max.isEmpty()&&max.size()==min.size())
result[i]=max.peek();
else {
result[i]=min.peek();
}
}
return result;
}
}