力扣HOT100之堆:295. 数据流的中位数
这道题第一次做,属于是设计题,没啥思路,我直接去看灵神的题解了,感觉灵神这一题的思路写的还比较通俗易懂。
这道题主要是要设计出一种数据结构,能够方便的算出中位数,这里也可以用数组来实现,但是每一次计算中位数都需要将数组进行排序,十分耗时,我们希望设计这样一种结构:当我们需要计算中位数时,应当以O(1)
的时间复杂度找到中间或者中间的两位数,并直接计算,对于其他元素我们并不关心。
综上,我们可以用两个优先队列(堆)来实现,一个定义为最大堆,用于存储较小的一半元素,另一个定义为最小堆,用于存储较大的另一半元素,因此,右侧的任意总是大于等于左侧的所有元素。我们规定:左侧的元素最多仅比右侧的元素多一个,右侧的元素个数在任何情况下都不会超过左侧元素。在此基础上,我们就可以进行进一步的分析:
- 当左侧的元素个数大于右侧时,我们需要将元素插入到右侧,由于待插入的元素可能非常小,需要加入到左边(或者待插入的元素非常大,需要加入到右边),我们需要先将待插入元素添加到左侧的最大堆中,由最大堆自动将其中的最大元素推送至堆顶,然后再将堆顶元素转移到右侧的最小堆中,这样就实现了元素添加到右侧(由于待添加的新元素最终不一定会添加到右边,需要由最大堆自动挑选出合适的元素,将其推送给右侧的最小堆)。
- 否则,就是左侧的元素个数等于右侧,我们需要选出一个合适的元素将其添加到左侧,这一个挑选元素的过程也需要由右侧的最小堆自动完成,我们先将新元素直接添加到右侧的最小堆,然后由最小堆挑选出最小元素,并推送至堆顶,再将堆顶元素转移到左侧的最大堆中。
至于计算中位数,就很简单了,由于题目保证在计算中位数的时候至少已经添加了一个元素,所以我们只需要判断最大堆与最小堆的元素个数大小关系,如果最大堆的元素数量更大,则说明当前总的元素个数为奇数个,直接返回最大堆的堆顶元素即可;否则,就意味着最大堆和最小堆的元素个数相等,我们分别将最大堆和最小堆的堆顶元素取出求均值即可。
class MedianFinder {
public:priority_queue<int, vector<int>, less<int>> max_heap; //最大堆,左侧priority_queue<int, vector<int>, greater<int>> min_heap; //最小堆,右侧MedianFinder() {}void addNum(int num) {if(max_heap.size() > min_heap.size()){//需要将元素添加到右侧max_heap.push(num);min_heap.push(max_heap.top());max_heap.pop();}else{//需要添加到左侧min_heap.push(num);max_heap.push(min_heap.top());min_heap.pop();}}double findMedian() {return max_heap.size() > min_heap.size() ? max_heap.top() : (max_heap.top() + min_heap.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();*/