zoukankan      html  css  js  c++  java
  • 295. Find Median from Data Stream

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

    For example,

    [2,3,4], the median is 3

    [2,3], the median is (2 + 3) / 2 = 2.5

    Design a data structure that supports the following two operations:

    • void addNum(int num) - Add a integer number from the data stream to the data structure.
    • double findMedian() - Return the median of all elements so far.

    Example:

    addNum(1)
    addNum(2)
    findMedian() -> 1.5
    addNum(3) 
    findMedian() -> 2
    

    Follow up:

    1. If all integer numbers from the stream are between 0 and 100, how would you optimize it?
    2. If 99% of all integer numbers from the stream are between 0 and 100, how would you optimize it?
    class MedianFinder {
    
        /** initialize your data structure here. */
        private List<Integer> list;
        public MedianFinder() {
            this.list = new ArrayList();
        }
        
        public void addNum(int num) {
            this.list.add(num);
        }
        
        public double findMedian() {
            Collections.sort(this.list);
            if(this.list.size() % 2 != 0) return  this.list.get(this.list.size() / 2);
            else{
                int m = this.list.size() / 2;
                return (this.list.get(m - 1) + this.list.get(m))/ 2.0; 
            }
        }
    }
    
    /**
     * Your MedianFinder object will be instantiated and called as such:
     * MedianFinder obj = new MedianFinder();
     * obj.addNum(num);
     * double param_2 = obj.findMedian();
     */

    但是这道题的难点必然在于如何优化。

    重点来了:

    java有个queue叫priorityQueue,数据存放在里面默认是从小到大排列,但是里面用了compare()方法,所以我们可以重写让它从大到小排列

    https://www.cnblogs.com/wei-jing/p/10806236.html

    //自定义比较器,降序排列
    static Comparator<Integer> cmp = new Comparator<Integer>() {
          public int compare(Integer e1, Integer e2) {
            return e2 - e1;
          }
        };
    public static void main(String[] args) {
            //不用比较器,默认升序排列
            Queue<Integer> q = new PriorityQueue<>();
            q.add(3);
            q.add(2);
            q.add(4);
            while(!q.isEmpty())
            {
                System.out.print(q.poll()+" ");
            }
            /**
             * 输出结果
             * 2 3 4 
             */
            //使用自定义比较器,降序排列
            Queue<Integer> qq = new PriorityQueue<>(cmp);
            qq.add(3);
            qq.add(2);
            qq.add(4);
            while(!qq.isEmpty())
            {
                System.out.print(qq.poll()+" ");
            }
            /**
             * 输出结果
             * 4 3 2 
             */
    }

    或者用大牛逼lambda表达式:

                Queue<Integer> qq = new PriorityQueue<>((a, b) -> b - a);//从大到小
                Queue<Integer> qq1 = new PriorityQueue<Integer>((a,b) -> a - b);//从小到大

    下面将使用这个特性创造一个maxHeap(一个根大于等于子节点的二叉树),一个minHeap(一个根小于等于节点的二叉树)。

    因为我们只想要median,所以知道中间两值特别重要,恰好用这两个heap就可以实现:maxHeap存前半个数组,使peek是中间值。同理minHeap存后半个,这样peek也是中间值(接近)。

    为了保证求median,我们必须要求这两个heap要balanced,否则会有[1],[2,3,4,5]这种情况。

    同时可以使maxHeap大于等于minHeap的长度,后面如果是奇数个可以直接返回maxHeap的peek。

    class MedianFinder {
         /** initialize your data structure here. */
        private PriorityQueue<Integer> maxHeap;
        private PriorityQueue<Integer> minHeap;
        /** initialize your data structure here. */
        public MedianFinder() {  
            maxHeap = new PriorityQueue<Integer>((a,b) -> b - a);//lambda表达式,匿名函数
            minHeap = new PriorityQueue<Integer>((a,b) -> a - b);
        }  
        public void addNum(int num) {
            if(maxHeap.isEmpty() || maxHeap.peek() >= num){
                maxHeap.add(num);
            }else{
                minHeap.add(num);
            }
            
            if(minHeap.size() + 1<maxHeap.size()) minHeap.add(maxHeap.poll());
            else if(maxHeap.size() < minHeap.size()){
                maxHeap.add(minHeap.poll());
            }
        }
        
        public double findMedian() {
            if(maxHeap.size() == minHeap.size()){
                return (maxHeap.peek() + minHeap.peek())/2.0;
            }
            return maxHeap.peek();
        }
    }

    最后附上java的优先队列解释https://www.cnblogs.com/wei-jing/p/10806236.html

  • 相关阅读:
    Linux下环境搭建(一)——java、tomcat配置
    Fiddler使用过程中容易忽略的小技巧
    Jenkins环境搭建(6)-修改自动化测试报告的样式
    Jmeter——JSON Extractor后置处理器介绍2
    Jmeter——实现Basic Auth方式登录
    Jmeter——JSON Extractor后置处理器介绍1
    基础拾遗------泛型详解
    利用委托与Lambada创建和调用webapi接口
    quartz.net任务调度:源码及使用文档
    quartz.net插件类库封装(含源码)
  • 原文地址:https://www.cnblogs.com/wentiliangkaihua/p/11770125.html
Copyright © 2011-2022 走看看