方法一:
双堆法(最大堆+最小堆)
当前两个堆中数据个数为偶数时:
如果新插入数据小于或等于大堆的堆顶
,则说明新数据应该插入大堆;此时我们先将大堆堆顶插入小堆中,然后再将新数据插入大堆。- **
否则
**直接将新数据插入小堆。
总而言之,为偶数时必须将小堆增加一个数,具体如何加取决于以上逻辑;
当前两个堆中数据个数为奇数时,有类似的处理方法;
以上操作确保两个堆的数据个数相差不超过1,以便于我们能够一O(1)时间复杂度取得中位数;
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
auto sz=maxh.size()+minh.size();
if(sz%2==0)
{
if(!maxh.empty()&&num<=maxh.top())
{
minh.push(maxh.top());
maxh.pop();
maxh.push(num);
}
else minh.push(num);
}
else
{
if(!minh.empty()&&num>=minh.top())
{
maxh.push(minh.top());
minh.pop();
minh.push(num);
}
else maxh.push(num);
}
}
double findMedian() {
auto sz=minh.size()+maxh.size();
if(sz%2==0)return (maxh.top()+minh.top())/2.0;
else return minh.top();
}
private:
priority_queue<int,vector<int>,less<int>>maxh;
priority_queue<int,vector<int>,greater<int>>minh;
};
双堆法不管是插入还是查找时间复杂度都是O(lgn),应该算是最优解法了;
还有一些其他方法:
方法二:
如数组+二分法,插入复杂度O(n),查找的复杂度O(1);
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
auto ret=lower_bound(data.begin(),data.end(),num);
data.insert(ret,num);
}
double findMedian() {
auto sz=data.size();
if(sz%2==0)return (data[sz/2]+data[sz/2-1])/2.0;
return data[sz/2];
}
vector<int>data;
};
方法三:
利用红黑树,插入的时间复杂度O(lgn),数据保持有序状态,但是唯一的问题是如何找到中位数。因此,引入两个指针,分别指向中间的两个数,如果总个数为数,两个指针指向同一个元素;否则,指向两个连续的数。
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
if(data.empty())
{
data.insert(num);
lmed=data.begin();
rmed=lmed;
return;
}
auto sz=data.size();
if(sz&1)
{
data.insert(num);
if(num<*lmed)
{
--lmed;
}
else
++rmed;
}
else
{
auto ret=data.insert(num);
if(num>=*lmed&&num<*rmed)
{
lmed=ret;
rmed=ret;
}
else if(num<*lmed)
{
--rmed;
}
else
++lmed;
}
}
double findMedian() {
if(data.size()&1)
return *lmed;
else
return (*lmed+*rmed)/2.0;
}
private:
multiset<int> data;
multiset<int>::iterator lmed;
multiset<int>::iterator rmed;
};