剑指Offer:数据流中的中位数Java/Python

1.题目描述

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

2.算法描述

什么是堆?

堆就是用数组实现的一颗完全二叉树,最大堆的根元素值最大,并且左右子树也是最大堆;同理最小堆的定义类似。
堆的定义

方法

用 两 个 堆 来 实 现 , 就 不 用 每 次 来 一 个 元 素 都 要 排 序 。 \red{用两个堆来实现,就不用每次来一个元素都要排序。}
初 始 化 两 个 堆 , m i n H e a p , m a x H e a p 分 别 为 最 小 堆 和 最 大 堆 。 \red{初始化两个堆,minHeap,maxHeap分别为最小堆和最大堆。} minHeap,maxHeap
插 入 元 素 操 作 : 当 一 个 元 素 进 入 数 据 流 时 , \red{插入元素操作:当一个元素进入数据流时,}
     若 数 据 流 中 已 有 奇 数 个 元 素 , 则 该 元 素 先 进 入 到 最 小 堆 中 , 然 后 将 最 小 堆 的 根 元 素 弹 出 并 进 入 到 最 大 堆 中 ; \red{\ \ \ \ 若数据流中已有奇数个元素,则该元素先进入到最小堆中,然后将最小堆的根元素弹出并进入到最大堆中;}     ,
     若 数 据 流 中 已 有 偶 数 个 元 素 , 则 该 元 素 先 进 入 到 最 大 堆 中 , 然 后 将 最 大 堆 的 根 元 素 弹 出 并 进 入 到 最 小 堆 中 。 \red{\ \ \ \ 若数据流中已有偶数个元素,则该元素先进入到最大堆中,然后将最大堆的根元素弹出并进入到最小堆中。}     ,
经过上述操作之后:
最小堆中装的是整个数据流从小到大的后一半元素(如果是奇数个元素,则还要多一个),
最大堆中装的是整个数据流从小到大的前一半元素。

返 回 中 位 数 操 作 : \red{返回中位数操作:}
     若 数 据 流 中 的 元 素 是 奇 数 个 元 素 , 则 返 回 最 小 堆 的 根 元 素 ; \red{\ \ \ \ 若数据流中的元素是奇数个元素,则返回最小堆的根元素;}     
     否 则 , 则 返 回 最 小 堆 的 根 元 素 和 最 大 堆 根 元 素 的 平 均 值 。 \red{\ \ \ \ 否则,则返回最小堆的根元素和最大堆根元素的平均值。}     

3.代码描述

3.1.Java代码

import java.util.*;
public class Solution {
    private int count = 0;
    PriorityQueue minHeap = new PriorityQueue<>();
    PriorityQueue maxHeap = new PriorityQueue<>((o1,o2)->o2-o1);
    public void Insert(Integer num) {
        if(count % 2 == 0){
            //当数据总数为偶数时,新加入的元素,应当进入小根堆
            //不是直接进入小根堆,而是经大根堆筛选后取大根堆中最大元素进入小根堆
             //新加入的元素先入到大根堆,由大根堆筛选出堆中最大的元素
            maxHeap.offer(num);
            int elem = maxHeap.poll();
            minHeap.offer(elem);
        }
        else{
            //当数据总数为奇数时,新加入的元素,应当进入大根堆
            //注意不是直接进入大根堆,而是经小根堆筛选后取小根堆中最大元素进入大根堆
            //新加入的元素先入到小根堆,由小根堆筛选出堆中最小的元素
            minHeap.offer(num);
            int elem = minHeap.poll();
            maxHeap.offer(elem);
        }
        count++;
    }

    public Double GetMedian() {
        if(count % 2 == 0){//如果是偶数个数  就把小顶堆的根元素和大顶堆的根元素 拿出
            return (minHeap.peek() + maxHeap.peek())/2.0;
        }
        else{//如果是奇数个数 那说明中位数就在小顶堆的根的位置
            return minHeap.peek()/1.0;
        }
    }


}

3.2.Python代码

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data = []
    def Insert(self, num):
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,data):
        length=len(self.data)
        if length%2==0:
            return (self.data[length//2]+self.data[length//2-1])/2.0
        else:
            return self.data[int(length//2)]

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