题意整理

  • 需要一个数据结构来存储从数据流吐出的整数。
  • 每收到一个整数,都可以得到当前数据结构中所有整数的中位数。

方法一(大顶堆与小顶堆)

1.解题思路

  • 初始化一个大顶堆和一个小顶堆。
  • 当两个堆大小相等时,将当前元素先入大顶堆,再弹出大顶堆的堆顶元素,将弹出的堆顶元素入小顶堆;如果两个堆大小不相等,则先将当前元素入小顶堆,再弹出堆顶元素入大顶堆。
  • 当两个堆大小相等时,数据流总共有偶数个,所以中位数为两个堆堆顶元素之和的一半;当大小不相等时,总共有奇数个,中位数恰好是小顶堆堆顶元素值。

动图展示:
图片说明

2.代码实现

import java.util.*;
public class Solution {
    /**
     * the medians
     * @param operations int整型二维数组 ops
     * @return double浮点型一维数组
     */
    public double[] flowmedian (int[][] operations) {
        //初始化结果数组
        int len=0;
        for(int[] opera:operations){
            if(opera[0]==2){
                len++;
            }
        }
        double[] res=new double[len];

        //初始化MedianHolder类
        MedianHolder median=new MedianHolder();
        int id=0;
        for(int[] opera:operations){
            //如果opt=1,则加入到结构中
            if(opera[0]==1){
                median.addNum(opera[1]);
            }
            //如果opt=2,则取出当前中位数
            else{
                res[id++]=median.findMedian();
            }
        }

        return res;
    }

    class MedianHolder{
        PriorityQueue<Integer> min;
        PriorityQueue<Integer> max;

        MedianHolder() {
            min=new PriorityQueue<>();
            max=new PriorityQueue<>((o1,o2)->o2-o1);
        }

        //添加当前数字
        public void addNum(int num) {
            if(min.size()==max.size()){
                max.offer(num);
                min.offer(max.poll());
            }
            else{
                min.offer(num);
                max.offer(min.poll());
            }
        }

        //查找当前中位数
        public double findMedian() {
            //如果数据流中没有数字,则返回-1
            if(min.size()==0&&max.size()==0) return -1.0;
            if(min.size()==max.size()){
                return (min.peek()+max.peek())/2.0;
            }
            else{
                return min.peek();
            }
        }
    }
}

3.复杂度分析

  • 时间复杂度:堆的插入和弹出操作的时间复杂度都是图片说明 ,获取堆顶元素不需要重新调整堆,可以在图片说明的时间内找到堆顶元素。所以添加的时间复杂度是图片说明,查找的时间复杂度是图片说明
  • 空间复杂度:假设数据流的大小为n,最坏情况下,大顶堆或小顶堆的大小为n,所以空间复杂度为图片说明

方法二(维护递增数据流+二分查找)

1.解题思路

核心代码的思路是用list维护一个单调递增的数据流,当有数据进来时,通过二分查找找到这个数在list中的位置,然后插入到这个对应的位置。当list的容量是奇数时,中间的那个数即是数据流的中位数;当list的容量是偶数时,中间两个数的平均值即是数据流的中位数。

2.代码实现

import java.util.*;


public class Solution {
    /**
     * the medians
     * @param operations int整型二维数组 ops
     * @return double浮点型一维数组
     */
    public double[] flowmedian (int[][] operations) {
        //初始化结果数组
        int len=0;
        for(int[] opera:operations){
            if(opera[0]==2){
                len++;
            }
        }
        double[] res=new double[len];

        //初始化MedianHolder类
        MedianHolder median=new MedianHolder();
        int id=0;
        for(int[] opera:operations){
            //如果opt=1,则加入到结构中
            if(opera[0]==1){
                median.addNum(opera[1]);
            }
            //如果opt=2,则取出当前中位数
            else{
                res[id++]=median.findMedian();
            }
        }

        return res;
    }

    class MedianHolder{
        //维护一个单调递增的数据流
        List<Integer> list;

        MedianHolder() {
            list=new ArrayList<>();
        }

        public void addNum(int num) {
            //如果数据流为空或者num大于数据流最大值,则直接添加
            if(list.size()==0||list.get(list.size()-1)<=num){
                list.add(num);
                return;
            }
            //找到num在数据流中的位置,并添加
            int index=binarySearch(list,num);
            list.add(index,num);
        }

        public double findMedian() {
            int n=list.size();
            //如果数据流中没有数字,则返回-1
            if(n==0) return -1.0;
            if(n%2==0){
                return (list.get(n/2)+list.get(n/2-1))/2.0;
            }
            else{
                return (double)list.get(n/2);
            }
        }

        //二分查找
        private int binarySearch(List<Integer> list,int target){
            int l=0,r=list.size()-1;
            while(l<r){
                int mid=l+(r-l)/2;
                if(list.get(mid)>=target){
                    r=mid;
                }
                else{
                    l=mid+1;
                }
            }
            return l;
        }
    }
}

3.复杂度分析

  • 时间复杂度:添加数据时,使用了二分查找来确定数据的位置,时间复杂度是图片说明,然后将数据添加到查找的位置,最坏情况下,需要移动n个元素,所以添加的时间复杂度是图片说明,查找中位数时,直接根据索引获取数据,所以查找的时间复杂度是图片说明
  • 空间复杂度:假设数据流的大小为n,list需要存储总共n个数据,所以空间复杂度为图片说明