JZ63 --- 数据流中的中位数

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

题解:
因为数据流是动态的,所以我们需要动态的调整整个数据序列,以及需要找出其中位数。我们知道,如果元素个数为偶数且序列有序,中位数为最中间两数之和。如果是奇数,就为最中间的那个数。

所以我们采用大堆和小堆,让元素在堆里排序。用大堆来存放排序后的前半部分元素,用小堆来存放后半部分数字。如果元素个数为偶数,返回(大堆顶顶元素 + 小堆队形元素)/ 2。如果元素个数为奇数,返回 大堆堆顶元素。
JZ63 --- 数据流中的中位数_第1张图片
如果再次添加一个数字,需要取这个序列的中位数,需要看当前元素个数为奇数还是偶数。

  • 如果是奇数,先将其与小堆堆顶元素比较
    (1)如果 num 大于当前小堆堆顶元素,则判定 num 是属于后半部分的数字,所以将其加进小堆。然后调整,将小堆堆顶元素加进大堆中,此时大堆的堆顶元素就是中位数。
    JZ63 --- 数据流中的中位数_第2张图片

(2)如果num 小于当前小堆的堆顶元素,则直接添加进大堆,此时大堆的堆顶元素就是中位数。

  • 如果是偶数,同理,先和大堆的堆顶元素进行比较
    (1)如果 num 小于当前大堆堆顶元素,则判定 num 是属于后前部分的数字,所以将其加进大堆。然后调整,将大堆堆顶元素加进小堆中。
    (2)如果num 大于当前大堆的堆顶元素,则直接添加进大堆。
    中位数为(大堆顶顶元素 + 小堆队形元素)/ 2 。
import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {
     

    //数据流中的中位数

    // 小堆,存放后半部分数字
    PriorityQueue<Integer> small = new PriorityQueue<> ();
    // 大堆,存放前半部分数字
    PriorityQueue<Integer> big = new PriorityQueue<> (new Comparator<Integer> () {
     
        @Override
        public int compare(Integer o1, Integer o2) {
     
            return o2.compareTo (o1);
        }
    });
    int cnt = 0;

    public void Insert(Integer num) {
     
        cnt++;
        if(cnt % 2 == 1){
     
            // 奇数,存入大堆中后调整
            // 前提是大堆不为空且当前num大于堆顶元素
            if(!small.isEmpty () && num > small.peek ()){
     
                small.add (num);
                // 小堆里最小的数字
                num = small.poll ();
            }
            // 小堆里最小的数字应该存进大堆
            big.add (num);
        }else{
     
             // 偶数
            if(!big.isEmpty () && num < big.peek ()){
     
                big.add (num);
                num = big.poll ();
            }
            small.add (num);
        }
    }

    public Double GetMedian() {
     
        double res = 0.0;
        if(cnt % 2 == 1){
     
            res = big.peek ();
        }else{
     
            res = (big.peek () + small.peek ()) / 2.0;
        }
        return res;
    }
}

你可能感兴趣的:(剑指offer)