题目描述
随机产生数字并传递给一个方法。你能否完成这个方法,在每次产生新值时,寻找当前所有值的中间值(中位数)并保存。
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[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
解题思路
- 连续中值,寻找中位数,可以用堆来做。申明一个left左边的大根堆,用来存放小值,右边right的小根堆,用来存放大值。
- addNum方法挂载到原型上,先判断num是否小于left中的堆顶元素,如果小于那么就push到left中。如果不小于就push到right中。对左右堆进去排序。left需要维护一个大根堆,所以是按照从小到大排序。right需要维护一个小根堆,所以是按照从大到小排序。
- 构造reverse方法,要对新加入的数据,左右堆进行数量的控制。必须保证左边的长度和右边的长度必须相等,或者左边长度比右边长度多1.
- 最后执行findMedian中值方法,需要先判断当前左右堆得长度,长度一样,那么取出左右堆顶元素进行相加除2.不等那么就返回left大根堆得堆顶元素。
代码
var MedianFinder = function(){
this.left = [-Infinity];
this.right = [Infinify];
}
// 保证左右堆得值长度一样或者左堆长度比右堆长度大1
MedianFinder.prototype.reverse = function(num){
if(this.left.length - this.right.length >= 2){
this.right.push(this.left.pop());
}else if(this.right.length > this.left.length){
this.left.push(this.right.pop());
}
}
// 判断num是否大于左堆得堆顶元素
MedianFinder.prototype.addNum = function(num){
if(num <= this.left[this.left.length - 1]){
this.left.push(num);
this.left.sort((a, b) => a - b);
}else{
this.right.push(num);
this.right.sort((a, b) => b - a);
}
this.reverse();
}
// 根据左右堆的长度来取返回值
MedianFinder.prototype.findMedian = function(){
if(this.left.length === this.right.lenght){
return (this.left[this.left.lenght - 1] + this.right[this.right.lenght - 1]) / 2
}
return this.left[this.left.length - 1];
}