leetcode 295.数据流的中位数
(同时也是剑指offer面试题41)
题目:
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[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
进阶:
如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
解题思路
1. 插入排序
将数据用vector保存,每次插入一个数据后进行一次排序,返回中位数时只要返回数组长度的一半的下标位置即可。
时间复杂度:插入O(n),中位数O(1)。
空间复杂度O(n)。
2. 两个堆
本题的关键在于求中位数,在思路一中,排序好的数组最中间即是求得中位数的值,所以可以用一个最大堆维护左半边数组,一个最小堆维护右半边数组,使得最大堆的堆顶为左半边数组的最大值,最小堆的堆顶为右半边数组的最小值。
class MedianFinder {
private:
priority_queue<int,vector<int>,less<int>> max_heap;
priority_queue<int,vector<int>,greater<int>> min_heap;
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
if(max_heap.empty()) {
max_heap.push(num);return ;
}
if(num>max_heap.top()){//当前插入值比大顶堆顶还大
if(min_heap.size()>=max_heap.size()){//且小顶堆数量比大顶堆大or等于
min_heap.push(num);//插入小顶堆
int tmp=min_heap.top();//弹出插入后的小顶堆最小值
min_heap.pop();
max_heap.push(tmp);//插入到大顶堆,保证数量差不会大于1
}
else{//小顶堆数量<大顶堆
min_heap.push(num);
}
}
else{//当前插入值比大顶堆小or等于
if(max_heap.size()<=min_heap.size()){//大顶堆数量不大于小顶堆数量
max_heap.push(num);
}
else{
int tmp=max_heap.top();
max_heap.pop();
min_heap.push(tmp);
max_heap.push(num);
}
}
}
double findMedian() {
double low=max_heap.top();
//当为列表总数为偶数
if(max_heap.size()==min_heap.size()){
double high=min_heap.top();
return (low+high)/2;
}
//否则当列表总数为奇数返回最大堆堆顶
return low;
}
};
时间复杂度:插入O(logn),求中位数O(1)。
空间复杂度:O(n)。