[路飞]_LeetCode_295. 数据流的中位数

180 阅读1分钟

题目

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。 double findMedian() - 返回目前所有元素的中位数。 示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

来源:力扣(LeetCode)leetcode-cn.com/problems/fi…

解题思路

  1. 把列表中的数字分两个区域,用一个大顶堆存小数,一个小顶堆存大数
  2. 两个堆都为空时添加到小数区,要添加的数小于等于小数区的最大元素时加入小数区,否则加入大数区
  3. 保持两个区的数字差不大于1
    • 如果小数区数字总数大于大数区 2 个时,小数区出队列一个元素入队列到大数区
    • 如果大数区数字总数大于小数区时,大数区出队列一个元素入队列到小数区
  4. 计算中位数
    • 两个区域数字总数相等时,取两个队列的顶部元素相加再除 2
    • 小数区数字多时中位数就是小数区的顶部元素

代码实现

var MedianFinder = function() {
    this.minQueue = new MaxPriorityQueue()  //3,2,1
    this.maxQueue = new MinPriorityQueue()  //4,5
};

/** 
 * @param {number} num
 * @return {void}
 */
MedianFinder.prototype.addNum = function(num) {
    if (this.minQueue.isEmpty() || num <= this.minQueue.front()['priority']) {
        this.minQueue.enqueue(num)
        if (this.minQueue.size() - this.maxQueue.size() > 1) {
            this.maxQueue.enqueue(this.minQueue.dequeue()['priority'])
        }
    } else {
        this.maxQueue.enqueue(num)
        if (this.maxQueue.size() > this.minQueue.size()) {
            this.minQueue.enqueue(this.maxQueue.dequeue()['priority'])
        }
    }
};

/**
 * @return {number}
 */
MedianFinder.prototype.findMedian = function() {
    if (this.minQueue.size() > this.maxQueue.size()) {
        return this.minQueue.front()['priority']
    }
    return (this.minQueue.front()['priority'] + this.maxQueue.front()['priority']) / 2.0
};

如有错误欢迎指出,欢迎一起讨论!