题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用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=2∗n+1,则允许 max 持有 n+1元素,而 min可以持有 n 个 元素。
如果
k
=
2
∗
n
k=2*n
k=2∗n,那么两个堆都是平衡的,并且每个堆都包含 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
}
}