【经典算法题】数据流的中位数
Leetcode 0295 数据流的中位数
分析
- 本题的考点:对顶堆。
- 本题考察数据结构:对顶堆。如下图:
-
当我们调用
findMedian()
时,根据up.size()+down.size()
的奇偶性返回对应的结果,如果为奇数,则返回down
的堆顶元素,否则返回up
和down
堆顶元素的平均值。 -
当我们调用
addNum(x)
函数时(1)如果
down
为空或者x
小于等于down
堆顶元素时,向down
中插入数据x
,并调整down
和up
,保证down
中元素和up
中元素个数相同或者多一个;(2)否则
down
非空并且x
大于down
堆顶元素,则向up
中插入数据x
,并调整down
和up
,保证up
中元素个数和不能多于up
中元素个数。
代码
- C++
class MedianFinder {
public:
priority_queue<int> down; // 大根堆
priority_queue<int, vector<int>, greater<int>> up; // 小根堆
MedianFinder() {
}
void addNum(int x) {
if (down.empty() || x <= down.top()) down.push(x);
else up.push(x);
if (up.size() > down.size()) down.push(up.top()), up.pop();
if (down.size() > up.size() + 1) up.push(down.top()), down.pop();
}
double findMedian() {
if ((down.size() + up.size()) % 2) return down.top();
else return (down.top() + up.top()) / 2.0;
}
};
- Java
class MedianFinder {
PriorityQueue<Integer> up = new PriorityQueue<>(); // 小顶堆
PriorityQueue<Integer> down = new PriorityQueue<>((o1, o2) -> o2 - o1); // 大顶堆
/** initialize your data structure here. */
public MedianFinder() {
}
public void addNum(int num) {
if (down.isEmpty() || num <= down.peek()) {
down.add(num);
if (down.size() > up.size() + 1) {
up.add(down.peek());
down.remove();
}
} else {
up.add(num);
if (up.size() > down.size()) {
down.add(up.peek());
up.remove();
}
}
}
public double findMedian() {
if ((up.size() + down.size()) % 2 == 1) return down.peek();
else return (up.peek() + down.peek()) / 2.0;
}
}
时空复杂度分析
-
时间复杂度:
addNum
: O ( l o g ( n ) ) O(log(n)) O(log(n)),findMedian
: O ( 1 ) O(1) O(1),n
是当前插入的数据数量。 -
空间复杂度: O ( n ) O(n) O(n)。