剑指Offer-41:数据流中的中位数

题目:数据流中的中位数

获取数据流中的中位数。如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

主要思路:

可以把输入数据平分成两部分,左边的数据都小于右边的数据,那么即使左右两边内部的数据没有排序,也可以根据左边最大的数和右边最小的数获取中位数。关键是,怎么获取左边的最大值和右边的最小值,并且保持左右两部分的个数之差不超过1?

可以借助最大堆和最小堆来实现,同时轮流把数据添加到左右部分。为了保证最小堆(右半部分)的所有元素都大于最大堆(左半部分)的所有元素,若当前数字本来要添加到最小堆中,但是当前数字比最大堆的最大值还小,那么,先把该数字添加到最大堆中,再把最大堆中的最大数字移出到最小堆中,这样就能保证最小堆中的所有元素都大于最大堆中的所有元素;若当前数字本来要添加到最大堆中,但是当前数字比最小堆的最小值还大,类似的,先添加该数字到最小堆,再移出最小堆的最小数字到最大堆。

时间复杂度:O(log(n))

 //思路:左大根堆,右小根堆
    PriorityQueue<Integer> leftMax = new PriorityQueue<>(
    new Comparator<Integer>() {
		@Override
		public int compare(Integer o1, Integer o2) {
			return o2 - o1;
		}
	});
    PriorityQueue<Integer> rightMin = new PriorityQueue<>();
    //注:应该均匀插入,先插左边,再插右边
    public void Insert(Integer num) {
    	//应该插左边
        if(leftMax.size() == rightMin.size()) {
        	//但是待插入值比右边的值大,则需要先插入右边,再取右边的最小值插入左边
        	if(!rightMin.isEmpty() && num > rightMin.peek()) {
        		rightMin.offer(num);
        		Integer min = rightMin.poll();
        		leftMax.offer(min);
        	}else {
        		leftMax.offer(num);
        	}
        //应该插入右边
        }else {
        	//但是待插入的值比左边的最大值小,则需要先插入左边,
        	//再取左边的最大值插入右边
        	if(!leftMax.isEmpty() && num < leftMax.peek()) {
        		leftMax.offer(num);
        		Integer max = leftMax.poll();
        		rightMin.offer(max);
        	}else {
        		rightMin.offer(num);
        	}
        }
    }

    public Double GetMedian() {
        //如果左边数目等于右边数目:各取顶点求均值
    	if(leftMax.size() == rightMin.size()) {
    		return (leftMax.peek() + rightMin.peek()) / 2.0;
    	}
    	//左边数目比较多,则取左边顶点
    	return new Double(leftMax.peek());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值