版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lv1224/article/details/82222719
题目
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[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
范围内,你将如何优化你的算法?
题解
这里要求中位数可以考虑用一个有序的数组来保存输入的数据,然后对于列表个数为偶数,则直接取出中间两个求均值即可,如果是奇数则取中间值即可。
代码:
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
auto it=upper_bound(nums.begin(),nums.end(),num);
nums.insert(it,num);
}
double findMedian() {
int n=nums.size();
if(n%2==0) return 1.0*(nums[n/2-1]+nums[n/2])/2;
else return nums[n/2];
}
vector<int> nums;
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
方法二
对于一个列表取中位数的时候我们只需要知道中间的数即可,至于整个数组是否有序并不重要,而用一个数组来保存列表,则需要对所有的数据排序,时间复杂度较高。既然不需要所有的数据有序,只需要中间的值,很自然想到把列表分成两半,分别用两个数据结构来保存,比如[1,3,4,5,6,7]
,对于这个列表,可以存为[1,3,4]
和[5,6,7]
,那么只需要中间的值就可以得出中位数了。可以考虑采用优先级队列,priority_queue
,左侧为数字越大优先级越高,右侧为数字越小优先级越高。那么取出两个优先级的top
值即可。
注: 优先级队列中,less
表示数字越大优先级越高,greater
表示数字越小优先级越高。
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
left.push(num);
if(left.size()-right.size()>1) {
right.push(left.top());
left.pop();
}
if(right.size()>0 && left.top()>right.top()){
int tmp=left.top();
left.pop();
left.push(right.top());
right.pop();
right.push(tmp);
}
}
double findMedian() {
if(left.size()==right.size()) return 1.0*(left.top()+right.top())/2;
else return left.top();
}
priority_queue<int, vector<int>,greater<int>> right;
priority_queue<int, vector<int>,less<int>> left;
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/