题目:
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
方法一:
思路:
1、数据流中的个数的奇偶性
(1)当数据流中的个数为奇数时,中位数只有一个。
(2)当数据流中的个数为偶数时,中位数有两个,一个左中位数,一个右中位数。
2、如果我们将每次addNum()后的集合都排好序,中位数就把它们分为两部分,一部分是“前有序数组”,另一部分是“后有序数组”。
3、(1)当数据流中的个数为奇数时,中位数就是前有序数组的最大值
(2)当数据流中的个数为偶数时,左中位数就是前有序数组的最大值,右中位数就是后有序数组的最小值。
4、
代码:
import java.util.PriorityQueue;
public class MedianFinder {
/**
* 当前大顶堆和小顶堆的元素个数之和
*/
private int count;
private PriorityQueue<Integer> maxheap;
private PriorityQueue<Integer> minheap;
/**
* initialize your data structure here.
*/
public MedianFinder() {
count = 0;
maxheap = new PriorityQueue<>((x, y) -> y - x);//大顶堆
minheap = new PriorityQueue<>();//无参默认小顶堆
}
public void addNum(int num) {
count += 1;
maxheap.offer(num);
minheap.add(maxheap.poll());//检索并删除maxheap队列的头,添加到minheap
// 如果两个堆合起来的元素个数是奇数,小顶堆要拿出堆顶元素给大顶堆
if ((count & 1) != 0) {
maxheap.add(minheap.poll());
}
}
public double findMedian() {
if ((count & 1) == 0) {
// 如果两个堆合起来的元素个数是偶数,数据流的中位数就是各自堆顶元素的平均值
return (double) (maxheap.peek() + minheap.peek()) / 2;
} else {
// 如果两个堆合起来的元素个数是奇数,数据流的中位数大顶堆的堆顶元素
return (double) maxheap.peek();
}
}
}