Question
Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.
Examples:
[2,3,4] , the median is 3
[2,3], the median is (2 + 3) / 2 = 2.5
Design a data structure that supports the following two operations:
void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.
For example:
add(1)
add(2)
findMedian() -> 1.5
add(3)
findMedian() -> 2
Algorithm:
数据结构 | addNum复杂度 | findMedian复杂度 |
---|---|---|
无序数组 | O(1) | O(n) |
有序数组 | O(n) | O(1) |
有序链表 | O(n) | O(1) |
二叉搜索树 | 平均O(logn),最差O(n) | 平均O(logn),最差O(n) |
AVL树 | O(logn) | O(logn) |
最大堆和最小堆 | O(logn) | O(logn) |
综上,由于大部分函数库都没有AVL这个数据结构,实现起来很复杂。
所以我们使用最大堆和最小堆来解决。
我们可以把数据分成2部分,位于容器左边部分的数据比右边的数据小。我们只要得到左边部分最大的数P1,和右边部分最小的数P2。
用最大堆实现左边的容器,最小堆实现右边的容器。
首先要保证数据平均分配到两个堆中,因此两个堆中数据数目之差不能超过1。
还要保证最大堆中里的所有数据都要小于最小堆中的数据。
addNum步骤:
1、如果要插入的数据小于左边的最大值,或者左边为空,插到左边,否则插入到右边
2、如果左-右数据之差超过1,把左边的顶端值,插入到右边
3、如果右-左数据之差超过1,把右边的顶端值,插到左边
findMedian步骤:
1、左边数据相等,两个顶端值求平均
2、左>右,左的顶端值
3、左<右,右的顶端值
由于,在C++中,优先队列priority_queue是以heap完成,所以我们用优先队列解决问题。
Code
class MedianFinder {
public:
priority_queue<int,vector<int>,greater<int> > min_heap;
priority_queue<int,vector<int>,less<int> > max_heap;
// Adds a number into the data structure.
void addNum(int num) {
if(max_heap.empty())
max_heap.push(num);
else if(num<max_heap.top()){
max_heap.push(num);
if(max_heap.size()-min_heap.size()>1){
min_heap.push(max_heap.top());
max_heap.pop();
}
}
else{
min_heap.push(num);
if(min_heap.size()-max_heap.size()>1){
max_heap.push(min_heap.top());
min_heap.pop();
}
}
}
// Returns the median of current data stream
double findMedian() {
if(max_heap.size()==min_heap.size())
return (max_heap.top()+min_heap.top())/2.0;
else if(max_heap.size()>min_heap.size())
return max_heap.top();
else
return min_heap.top();
}
};
// Your MedianFinder object will be instantiated and called as such:
// MedianFinder mf;
// mf.addNum(1);
// mf.findMedian();