题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
方法一:
数组插入进去然后再排序,这种情况插入时间效率是O(n),找中位数时间效率是O(1)。
class Solution {
vector<int> dataStream;
public:
void Insert(int num)
{
dataStream.push_back(num);
if (dataStream.size() > 1) {
for (int i = dataStream.size() - 1; i > 0; i--) {
if (dataStream[i] < dataStream[i-1])
swap(dataStream[i], dataStream[i-1]);
}
}
}
double GetMedian()
{
double Median;
int len = dataStream.size();
if (len % 2 != 0)
return (double)dataStream[len/2];
else
return ((double)dataStream[len/2] + (double)dataStream[len/2-1]) / 2;
}
};
方法二:
大顶堆和小顶堆。插入的时间效率是O(logn),找中位数的时间效率是O(1)。
使用c++ STL优先队列priority_queue:
priority_queue <int,vector<int>,greater<int> > minHeap;//构造小顶堆
priority_queue <int,vector<int>,less<int> > maxHeap;//构造大顶堆
思路:以中位数为分界点将整个输入数据分成两部分;
根据中位数的性质,当输入元素为奇数时,中位数位于存储前半部分数据的大顶堆中;当输入元素为偶数时,中位数位于存储后半部分数据的小顶堆中。在大顶堆中加入元素的后,将大顶堆中的最大的元素(maxHeap.top())加入到小顶堆中,在小顶堆中加入元素的后,将小顶堆中的最小的元素(minHeap.top())加入到大顶堆中。
class Solution {
int count = 0;
priority_queue <int,vector<int>,greater<int> > minHeap;
priority_queue <int,vector<int>,less<int> > maxHeap;
public:
void Insert(int num)
{
count++;
if (count % 2 != 0) {
minHeap.push(num);
maxHeap.push(minHeap.top());
minHeap.pop();
} else {
maxHeap.push(num);
minHeap.push(maxHeap.top());
maxHeap.pop();
}
}
double GetMedian()
{
if (count % 2 != 0)
return (double)maxHeap.top();
else
return (double)(minHeap.top() + maxHeap.top()) / 2;
}
};
方法三:
利用头文件algorithm中的make_heap()、push_heap()、pop_heap()
注意在使用以上三个函数是要注明less< int>()(表示降序序列,构造大顶堆),greater< int>()(表示升序序列,构造小顶堆);默认状态是构造大顶堆。
注意:pop_heap()的作用是:交换* first和 * (last-1), 然后把[first, last-1)建成一个max heap(默认状态下). 也就是说把堆顶的最大元素交换到区间尾,然后把除了尾部的元素的剩余区间重新调整成堆。注意此时并不是真正的删除,只是将原堆顶的最大元素交换到区间尾。在本题中需要调用pop_back才能将原堆顶元素彻底删除。
class Solution {
int count = 0;
vector<int> minHeap;
vector<int> maxHeap;
public:
void Insert(int num)
{
count++;
if (count % 2 != 0) {
minHeap.push_back(num);
push_heap(minHeap.begin(), minHeap.end(), greater<int>());
maxHeap.push_back(minHeap[0]);
push_heap(maxHeap.begin(), maxHeap.end(), less<int>());
pop_heap(minHeap.begin(), minHeap.end(), greater<int>());
minHeap.pop_back();
} else {
maxHeap.push_back(num);
push_heap(maxHeap.begin(), maxHeap.end(), less<int>());
minHeap.push_back(maxHeap[0]);
push_heap(minHeap.begin(), minHeap.end(), greater<int>());
pop_heap(maxHeap.begin(), maxHeap.end(), less<int>());
maxHeap.pop_back();
}
}
double GetMedian()
{
if (count % 2 != 0)
return (double)maxHeap[0];
else
return (double)(minHeap[0] + maxHeap[0]) / 2;
}
};