力扣HOT100之堆:295. 数据流的中位数

力扣HOT100之堆:295. 数据流的中位数_第1张图片
这道题第一次做,属于是设计题,没啥思路,我直接去看灵神的题解了,感觉灵神这一题的思路写的还比较通俗易懂。
这道题主要是要设计出一种数据结构,能够方便的算出中位数,这里也可以用数组来实现,但是每一次计算中位数都需要将数组进行排序,十分耗时,我们希望设计这样一种结构:当我们需要计算中位数时,应当以O(1)的时间复杂度找到中间或者中间的两位数,并直接计算,对于其他元素我们并不关心。
综上,我们可以用两个优先队列(堆)来实现,一个定义为最大堆,用于存储较小的一半元素,另一个定义为最小堆,用于存储较大的另一半元素,因此,右侧的任意总是大于等于左侧的所有元素。我们规定:左侧的元素最多仅比右侧的元素多一个,右侧的元素个数在任何情况下都不会超过左侧元素。在此基础上,我们就可以进行进一步的分析:

  1. 当左侧的元素个数大于右侧时,我们需要将元素插入到右侧,由于待插入的元素可能非常小,需要加入到左边(或者待插入的元素非常大,需要加入到右边),我们需要先将待插入元素添加到左侧的最大堆中,由最大堆自动将其中的最大元素推送至堆顶,然后再将堆顶元素转移到右侧的最小堆中,这样就实现了元素添加到右侧(由于待添加的新元素最终不一定会添加到右边,需要由最大堆自动挑选出合适的元素,将其推送给右侧的最小堆)。
  2. 否则,就是左侧的元素个数等于右侧,我们需要选出一个合适的元素将其添加到左侧,这一个挑选元素的过程也需要由右侧的最小堆自动完成,我们先将新元素直接添加到右侧的最小堆,然后由最小堆挑选出最小元素,并推送至堆顶,再将堆顶元素转移到左侧的最大堆中。
    至于计算中位数,就很简单了,由于题目保证在计算中位数的时候至少已经添加了一个元素,所以我们只需要判断最大堆与最小堆的元素个数大小关系,如果最大堆的元素数量更大,则说明当前总的元素个数为奇数个,直接返回最大堆的堆顶元素即可;否则,就意味着最大堆和最小堆的元素个数相等,我们分别将最大堆和最小堆的堆顶元素取出求均值即可。
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();
 */

你可能感兴趣的:(力扣HOT100,leetcode,算法,职场和发展)