一、题目描述
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[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: vector<int> vec; /** initialize your data structure here. */ MedianFinder() { } void addNum(int num) { vec.emplace_back(num); } double findMedian() { sort(vec.begin(),vec.end()); int n = vec.size(); return n&1?vec[n/2]:0.5*(vec[n/2-1]+vec[n/2]); } }; /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder* obj = new MedianFinder(); * obj->addNum(num); * double param_2 = obj->findMedian(); */
方法二:插入排序
class MedianFinder { public: vector<int> vec; /** initialize your data structure here. */ MedianFinder() { } void addNum(int num) { if(vec.empty()){ vec.emplace_back(num); }else{ vec.insert(lower_bound(vec.begin(),vec.end(),num),num); } } double findMedian() { int n = vec.size(); return n&1?vec[n/2]:0.5*(vec[n/2-1]+vec[n/2]); } };
方法三:两个堆实现
class MedianFinder { public: priority_queue<int,vector<int>,less<int> > lo; priority_queue<int,vector<int>,greater<int> > hi; public: /** initialize your data structure here. */ MedianFinder() { } void addNum(int num) { lo.push(num); hi.push(lo.top()); lo.pop(); if(lo.size()<hi.size()){ lo.push(hi.top()); hi.pop(); } } double findMedian() { return lo.size()>hi.size()?lo.top():((double)lo.top()+(double)hi.top())/2.0; } }; /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder* obj = new MedianFinder(); * obj->addNum(num); * double param_2 = obj->findMedian(); */
方法四:使用Multiset和双指针
class MedianFinder { public: multiset<int> data; multiset<int>::iterator lo_median, hi_median; /** initialize your data structure here. */ MedianFinder():lo_median(data.end()),hi_median(data.end()) { } void addNum(int num) { int n = data.size(); data.insert(num); if(n==0){ lo_median = data.begin(); hi_median = data.begin(); }else if(n&1){//原来set大小是奇数,两指针指向同一元素,插入元素后应指向不同元素 if(num<*lo_median){ lo_median--; }else{ hi_median++; } }else{//原来set大小是偶数,两指针指向相邻元素,插入元素后应指向相同元素 if(num>*lo_median&&num<*hi_median){ lo_median++; hi_median--; }else if(num>=*hi_median){//注意处理相等情况 lo_median++; }else{ lo_median=--hi_median; } } } double findMedian() { return (*lo_median+*hi_median)*0.5; } }; /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder* obj = new MedianFinder(); * obj->addNum(num); * double param_2 = obj->findMedian(); */