JZ63 数据流中的中位数——大顶堆、小顶堆

题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

题解

此题应该着重于考察大顶堆和小顶堆

之所以提供两个函数,就是想让大家动态的获取
比如插入之后,通过getmedian能立马获得中位数,需要动态的更新

具体思想可看:https://leetcode-cn.com/problems/find-median-from-data-stream/solution/shu-ju-liu-de-zhong-wei-shu-by-leetcode/

算法
两个优先级队列:

  • 用于存储较小一半数字的最大堆 max
  • 用于存储较大一半数字的最小堆 min

最大堆 max 允许存储的元素最多比最小堆 min 多一个。因此,如果我们处理了 k 元素:
如果 k = 2 ∗ n + 1 k=2*n+1 k=2n+1,则允许 max 持有 n+1元素,而 min可以持有 n 个 元素。
如果 k = 2 ∗ n k=2*n k=2n,那么两个堆都是平衡的,并且每个堆都包含 n 个元素。
这给了我们一个很好的特性,即当堆完全平衡时,中间值可以从两个堆的顶部派生。否则,最大堆 max 的顶部保留合法的中间值。

添加一个数 num:
将 num 添加到最大堆 max。因为max 收到了一个新元素,所以我们必须为 min 做一个平衡步骤。因此,从 max中移除最大的元素并将其提供给 min 。
在上一个操作之后,最小堆 min 可能会比最大堆 max 保留更多的元素。我们通过从 min 中去掉最小的元素并将其提供给 max 来解决这个问题。

上面的步骤确保两个堆能够平衡
但好像javascript中不提供堆的数据结构,因此如果我们要用大顶堆和小顶堆的思想解,还需要构造堆的构造函数,及维护堆的各种方法,可以在上面提供的链接中找到相应的具体代码。

这里我们先提供一种暴力解法的代码

代码:

let arr = [];
function Insert(num)
{
     
    // write code here
    arr.push(num);
    let len = arr.length - 1;
    while(len>0){
     
        if(arr[len] < arr[len-1]){
     
            [arr[len],arr[len-1]] = [arr[len-1],arr[len]];
            len--;
        }
        else
            break;
    }
}
function GetMedian(){
     
    // write code here
    if(!arr.length)
        return null;
    else if (arr.length % 2)
        return arr[(arr.length-1)/2];
    else{
     
        let midIndex = arr.length / 2;
        return (arr[midIndex] + arr[midIndex-1]) / 2
    }
}

你可能感兴趣的:(js_剑指Offer刷题)