整体思路还是让数组实现排序,只不过是将元素平均分配在一个大根堆和一个小根堆上?
原因: 假设数组已经排好顺序(从小到大),将数组均分为两份(left, right, left.length -right.length <=1 ),得到的数组有两个特征:
1.left里的元素都比right里的小
2. 如果原数组有奇数个元素,那么中位数肯定left里最大的那个,否则的话,就是
(max(left) + min (right)) / 2
所以基于上述特征所以选择用一个大顶堆来存放应该属于left里的元素,用一个小顶堆来存放应该属于right里的元素,最后根据原数组的个数是奇数还是偶数,来求出中位数
奇数位置的元素为什么要优先放在大顶堆?
原因: 也是根据上述特征, 再求中位数的过程中一定有left里最大(最左)的元素参与,要么直接就是它,要么就是让它和right最小相加再除以二。
static class BigComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
}
static Integer getMedian(int[] arr) {
if (arr == null) {
return null;
}
PriorityQueue<Integer> min = new PriorityQueue<>();
PriorityQueue<Integer> max = new PriorityQueue<>(new BigComparator());
for (int i = 0; i < arr.length; i++) {
if ((i & 1) > 0) { // 奇数位
if (min.isEmpty() && arr[i] <= min.peek()) {
max.add(arr[i]);
}else{
max.add(min.poll());
min.add(arr[i]);
}
}else {
if (max.isEmpty() || arr[i] >= max.peek()) {
min.add(arr[i]);
}else{
min.add(max.poll());
max.add(arr[i]);
}
}
}
if ((arr.length & 1) > 0) { // 说明中位数在大顶堆的第一个
return max.peek();
}else {
return (max.peek() + min.peek()) >> 1;
}
}