剑指offer:JZ63 数据流中的中位数

本文探讨了在数据流中高效求解中位数的方法,包括使用暴力排序和大小堆(大顶堆与小顶堆)策略。暴力排序的时间复杂度较高,而大小堆则能实现实时更新且保持时间复杂度较低。通过实例展示了两种方法的实现和性能对比。
摘要由CSDN通过智能技术生成

描述

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

示例

input:
[5,2,3,4,1,6,7,0,8]
output:
5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00
note:
数据流里面不断吐出的是5,2,3...,则得到的平均数分别为5,(5+2)/2,3...  

思路

1、暴力求解:直接添加+排序取中位数

该方法比较容易想到,直接使用一个数组来记录数据流,取中位数前先排序。该方法的关键在于排序算法的选取。本题中采用ArrayList存储元素,并使用sort或者用Collections.sort排序。时间复杂度为O(nlogn)。如果采用冒泡等排序,则时间复杂度为 O ( n 2 ) O(n^2) O(n2)

import java.util.*;
public class Solution {
    ArrayList<Integer> arr = new ArrayList<>();
    public void Insert(Integer num) {
        arr.add(num);
    }

    public Double GetMedian() {
    	//Collections.sort(arr); //21ms
        arr.sort((o1, o2)->o1.compareTo(o2)); //116ms
        int mid = arr.size() >> 1;
        if( (arr.size()&1) == 0) return (arr.get(mid)+arr.get(mid-1))/2.0;
        else return arr.get(mid)*1.0;
    }
}

在这里插入图片描述
在这里插入图片描述

1、大小堆

由于需要求中位数,因此考虑将数组按照中位数mid分为两部分:比中位数小的大顶堆max_heap、比中位数大或相等的小顶堆min_heap。这样可以保证:max_heap.peek() < mid <= min_heap.peek()。在实现上,先将元素放入大顶堆排序,然后取大顶堆的堆顶元素放入小顶堆,如果小顶堆大小比大顶堆多2,则让两个顶堆大小一样。

import java.util.*;
public class Solution {
    //小顶堆存储较大元素,大顶堆存储较小的元素
    PriorityQueue<Integer> min_heap = new PriorityQueue<>();
    PriorityQueue<Integer> max_heap = new PriorityQueue<>(Comparator.reverseOrder());
    public void Insert(Integer num) {
        //大顶堆筛选后,将大顶堆中最大的元素放入小顶堆
        max_heap.offer(num);
        min_heap.offer(max_heap.poll());
        //由于第1个元素放入在min_heap中,所以奇数个元素时min_heap多1个
        if(min_heap.size() - max_heap.size() > 1){//不一致时平衡两堆
            max_heap.offer(min_heap.poll());
        }
    }

    public Double GetMedian() {
        int min_top =  min_heap.peek();
        return min_heap.size() > max_heap.size() ? min_top*1.0 : (min_top + max_heap.peek())/2.0;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值