中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[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
思路:
使用大小堆一起来位数数组中位数。
将数据流保存在一个列表中,并在添加元素时保持数组有序。
建立一个小顶堆A和一个大顶堆B,并规定A保存较大的一半,B保存较小的一半。
则A的堆顶元素为较大的一半的最小值,B的堆顶元素为较小的一半的最大值。
定义m,n分别为A,B两个堆中的元素个数,N为总数,N=m+n。
1.addNum(num)
1.当m==n,N为偶数,则向A中添加一个元素。
两边元素个数相等时,加入到左边的元素中,即大顶堆中,加入的过程需要先将元素加入小顶堆,调整之后,将堆顶加入大顶堆,即能保证加入的元素一定是右边元素中最小的。
2.当m!=n,N为基数,则向B中添加一个元素。
反之,左边元素比右边元素多一个,加入到右边元素中,即小顶堆中,加入的过程需要先将元素加入大顶堆,调整之后,将堆顶加入小顶堆,即能保证加入的元素一定是左边元素中最大的。
2.findMedian()
1.当m==n 时,中位数为(A的堆顶元素+B的堆顶元素)/2
2.当m!=n时,中位数为A的堆顶元素。
AC代码:(C++)
class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int, vector<int>, less<int>> maxHeap; //大顶堆,堆顶为小的一半元素的最大值
priority_queue<int, vector<int>, greater<int>> minHeap; //小顶堆,堆顶为大的一半元素的最小值
MedianFinder() {
}
void addNum(int num) {
if (maxHeap.size() == minHeap.size()) {
//两边元素个数相等时,加入到左边的元素中,即大顶堆中
//加入的过程需要先将元素加入小顶堆,调整之后,将堆顶加入大顶堆
//即能保证加入的元素一定是右边元素中最小的
minHeap.push(num);
int top = minHeap.top();
minHeap.pop();
maxHeap.push(top);
} else {
//反之,左边元素比右边元素多一个,加入到右边元素中,即小顶堆中
//加入的过程需要先将元素加入大顶堆,调整之后,将堆顶加入小顶堆
//即能保证加入的元素一定是左边元素中最大的
maxHeap.push(num);
int top = maxHeap.top();
maxHeap.pop();
minHeap.push(top);
}
}
double findMedian() {
if (maxHeap.size() == minHeap.size()) {
return (maxHeap.top() + minHeap.top()) * 1.0 / 2;
} else {
return maxHeap.top() * 1.0;
}
}
};