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内核设计与实现——进程管理
    技术派-常用的一些VS相关的宏名
    假如面试3道小学数学题,你可否会?
    技术派-不用sqrt手工计算平方根
    观察者-学历差距造成的差距有多大
    10G文件如何对里面单词出现排序
  • 原文地址:https://www.cnblogs.com/wentiliangkaihua/p/11770125.html
Copyright © 2011-2022 走看看