剑指offer 面试题64 数据流中的中位数

剑指offer 面试题64 数据流中的中位数

题目:
如何得到一个数据流中的中位数?
如果从数据流中读出期数个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

package algorithm.ac.foroffer.top70;

import org.junit.Test;

import java.util.*;

/**
 * description:
 *
 * @author liyazhou
 * @create 2017-06-19 16:26
 *
 * 面试题64:数据流中的中位数
 *
 * 题目:
 *      如何得到一个数据流中的中位数?
 *      如果从数据流中读出期数个数值,那么中位数就是所有数值排序之后位于中间的数值。
 *      如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
 *
 * 考查点:
 *      1. 查找
 *      2. 最大堆和最小堆
 *
 * 思路:
 *      1. 将数据流中的数据保存到两个容器中,这两个容器需要满足以下的条件:
 *            a. 保证一个容器中的最大值不大于另一个容器中的最小值
 *            b. 保证两个容器中的元素个数相差 0 或者 1
 *            c. 存放较小值的容器能够快读获取到最大值,存放较大值的容器能够快速获取到最小值
 *      2. 这个数据结构就是最大堆和最小堆
 *      3. 步骤:
 *            当新输入一个数据时,
 *            若两个容器中元素的总数目是偶数,
 *              则将最大堆中的最大值和当前值中较大值保存到最小堆中,较小者保存到最大堆中。
 *              (为了保证一个容器中的最大值不大于另一个容器中的最小值)
 *            若两个容器中元素的总数目是奇数,
 *              则将最小堆中的最小值和当前值中的较小者保存到最大堆中,较大者保存到最小堆中。
 *              (为了保证一个容器中的最大值不大于另一个容器中的最小值)
 *            通过对两个容器中总元素个数的判断,控制新的数据保存到哪一个堆中,实现了两个容器中元素个数相差为 0 或者 1。
 *            此时,已然满足了 1 中的 a、b 和 c 三个条件。
 *
 *
 *
 */
public class Test64 {
    private Queue<Integer> minHeap = new PriorityQueue<>();
    // Comparator<Integer> reverse = new Comparator<Integer>(){
    //    @Override public int compare(Integer obj1, Integer obj2){ return obj2 - obj1; }
    // };
    private Queue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());

    public void insert(int num){
        if (((minHeap.size() + maxHeap.size()) & 1) == 0){ // 数字的总数为偶数,将新的数据插入到最小堆中(最小堆中保存的都是较大的数字)
            // 若当前值最大堆中的最大值小,则将当前数字和最大数字交换(为了保证最大堆的最大值始终不大于最小堆中的最小值)
            // 即,将当前数字保存到最大堆中,将最大堆中的最大数字弹出并保存到最小堆中
            if (maxHeap.size() > 0 && num < maxHeap.peek()){
                maxHeap.offer(num);
                num = maxHeap.poll();
            }
            minHeap.offer(num);
        }
        else{  // 数字的总数为奇数,将新的数据插入到最大堆中(最大堆中保存的都是较小的数字)
            // 若当前值比最小堆中的最小值大,则将当前数字和最小值交换(为了保证最大堆中的最大值始终不大于最小堆中的最小值)
            // 即,将当前数字存放到最小堆中,将最小堆中的最小数字弹出并保存到最大堆中
            if (minHeap.size() > 0 && num > minHeap.peek()){
                minHeap.offer(num);
                num = minHeap.poll();
            }
            maxHeap.offer(num);
        }
    }


    public double getMedain(){
        int size = minHeap.size() + maxHeap.size();
        if (size == 0) throw new IllegalArgumentException("Argument is illegal.");
        double medain = -1;
        if ((size & 1) == 1) medain = minHeap.peek();
        else                 medain = (minHeap.peek() + maxHeap.peek()) / 2.0;
        return medain;
    }

    @Test
    public void test(){
        Random random = new Random();
        int N = 10;
        for (int i = 0; i < N; i ++)  insert(random.nextInt(100));

        for (int i = 0; i < 5; i ++) {
            insert(random.nextInt(100));
            System.out.println("maxHeap : " + maxHeap);
            System.out.println("minHeap : " + minHeap);
            System.out.println(getMedain());
            System.out.println();
        }
    }
}

测试结果:

maxHeap : [53, 33, 42, 4, 28]
minHeap : [55, 76, 64, 99, 91, 92]
55.0

maxHeap : [53, 33, 42, 4, 28, 2]
minHeap : [55, 76, 64, 99, 91, 92]
54.0

maxHeap : [42, 33, 16, 4, 28, 2]
minHeap : [53, 76, 55, 99, 91, 92, 64]
53.0

maxHeap : [42, 33, 16, 4, 28, 2, 16]
minHeap : [53, 76, 55, 99, 91, 92, 64]
47.5

maxHeap : [42, 33, 16, 4, 28, 2, 16]
minHeap : [53, 70, 55, 76, 91, 92, 64, 99]
53.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值