剑指offer63:数据流中的中位数
题目描述:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
本题最开始简单的理解为求中位数,使用的是快排的思想,当数据元素为奇数个时,求第n/2大的数,当元素个数为偶数时,先求n/2个数,然后对右边的求出一个最小值。
看了别人的做法,发现应该把这道题理解为一个在线算法题。关键是使用两个堆,最大化堆存储前n/2个数,最小化堆存储后n/2个数,当元素个数为偶数个时,元素num放入最小化堆中;元素个数为奇数时,元素num放入最大化堆。最终,当元素个数为奇数时,中位数就是最小化堆的堆顶;当元素个数为偶数时,中位数是最小化堆和最大化堆的堆顶的均值。
1 class Solution { 2 private: 3 vector<int> minHeap; //数组中的后一半元素组成一个最小化堆 4 vector<int> maxHeap; //数组中的前一半元素组成一个最大化堆 5 public: 6 void Insert(int num) { 7 if(((minHeap.size()+maxHeap.size()) & 1) == 0) { //偶数数据的情况下,则在最小堆中插入元素 8 if(maxHeap.size() > 0 && num < maxHeap[0]) { 9 maxHeap.push_back(num); 10 push_heap(maxHeap.begin(), maxHeap.end(), less<int>()); 11 num=maxHeap[0]; 12 pop_heap(maxHeap.begin(), maxHeap.end(), less<int>()); 13 maxHeap.pop_back(); 14 } 15 minHeap.push_back(num); //把前一半找到的最大值放到后一半中 16 push_heap(minHeap.begin(), minHeap.end(), greater<int>()); 17 } else { 18 if(minHeap.size() > 0 && num > minHeap[0]) { //奇数数据的情况下,则在最大堆中插入元素 19 minHeap.push_back(num); 20 push_heap(minHeap.begin(), minHeap.end(), greater<int>()); 21 num=minHeap[0]; 22 pop_heap(minHeap.begin(), minHeap.end(), greater<int>()); 23 minHeap.pop_back(); 24 } 25 maxHeap.push_back(num); //把后一半找到的最大值放到前一半中 26 push_heap(maxHeap.begin(), maxHeap.end(), less<int>()); 27 } 28 } 29 30 double GetMedian() { 31 int size=minHeap.size() + maxHeap.size(); 32 if(size==0) return -1; 33 if((size&1) != 0) { 34 return (double) minHeap[0]; 35 } else { 36 return (double) (maxHeap[0] + minHeap[0]) / 2; 37 } 38 } 39 };