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?
     

    Approach #1: C++. [Heap/priority_queue]

    class MedianFinder {
    public:
        /** initialize your data structure here. */
        MedianFinder() {
            
        }
        
        void addNum(int num) {
            if (l_.empty() || num < l_.top()) {
                l_.push(num);
            } else {
                r_.push(num);
            }
            
            if (r_.size() > l_.size()) {
                l_.push(r_.top());
                r_.pop();
            } 
            if (l_.size() - r_.size() == 2) {
                r_.push(l_.top());
                l_.pop();
            }
        }
        
        double findMedian() {
            if (l_.size() > r_.size()) return static_cast<double>(l_.top());
            else return static_cast<double>(l_.top() + r_.top()) / 2;
        }
        
    private:
        priority_queue<int, vector<int>, less<int>> l_;
        priority_queue<int, vector<int>, greater<int>> r_;
    };
    
    /**
     * Your MedianFinder object will be instantiated and called as such:
     * MedianFinder obj = new MedianFinder();
     * obj.addNum(num);
     * double param_2 = obj.findMedian();
     */
    

      

    Approach #2: C++. [blance binary search tree]

    // Author: Huahua
    // Running time: 172 ms
    class MedianFinder {
    public:
        /** initialize your data structure here. */
        MedianFinder(): l_(m_.cend()), r_(m_.cend()) {}
        
        // O(logn)
        void addNum(int num) {
            if (m_.empty()) {
                l_ = r_ = m_.insert(num);
                return;
            }
            
            m_.insert(num);
            const size_t n = m_.size();    
            
            if (n & 1) {
                // odd number
                if (num >= *r_) {         
                    l_ = r_;
                } else {
                    // num < *r_, l_ could be invalidated
                    l_ = --r_;
                }
            } else {
                if (num >= *r_)
                    ++r_;
                else
                    --l_;
            }
        }
        // O(1)
        double findMedian() {
            return (static_cast<double>(*l_) + *r_) / 2;
        }
    private:
        multiset<int> m_;
        multiset<int>::const_iterator l_;  // current left median
        multiset<int>::const_iterator r_;  // current right median
    };
    

    @huahuajiang

    Appraoch #3: Java. [balnce binary search tree]

    class MedianFinder {
        private Node root;
        private Node medianLeft;
        private Node medianRight;
        private int size;
    
        /** initialize your data structure here. */
        public MedianFinder() {
            
        }
        
        public void addNum(int num) {
            if (root == null) {
                root = new Node(num);
                medianLeft = root;
                medianRight = root;
            } else {
                root.addNode(num);
                if (size % 2 == 0) {
                    if (num < medianLeft.data) {
                        medianRight = medianLeft;
                    } else if (medianLeft.data <= num && num < medianRight.data) {
                        medianLeft = medianLeft.successor();
                        medianRight = medianRight.predecessor();
                    } else if (num >= medianRight.data) {
                        medianLeft = medianRight;
                    }
                } else {
                    if (num < medianLeft.data) {
                        medianLeft = medianLeft.predecessor();
                    } else {
                        medianRight = medianRight.successor();
                    }
                }
            }
            size++;
        }
        
        public double findMedian() {
            return (medianLeft.data + medianRight.data) / 2.0;
        }
        
        class Node {
            private Node parent;
            private Node left;
            private Node right;
            private int data;
            
            public Node(int data) {
                this.data = data;
            }
            
            public void addNode(int data) {
                if (data >= this.data) {
                    if (right == null) {
                        right = new Node(data);
                        right.parent = this;
                    } else {
                        right.addNode(data);
                    }
                } else {
                    if (left == null) {
                        left = new Node(data);
                        left.parent = this;
                    } else {
                        left.addNode(data);
                    }
                }
            }
            
            public Node predecessor() {
                if (left != null) {
                    return left.rightMost();
                }
                
                Node predecessor = parent;
                Node child = this;
                
                while (predecessor != null && child != predecessor.right) {
                    child = predecessor;
                    predecessor = predecessor.parent;
                }
                
                return predecessor;
            }
            
            public Node successor() {
                if (right != null) {
                    return right.leftMost();
                }
                
                Node successor = parent;
                Node child = this;
                 while (successor != null && child != successor.left) {
                     child = successor;
                     successor = successor.parent;
                 }
                
                return successor;
            }
            
            public Node leftMost() {
                if (left == null) return this;
                return left.leftMost();
            }
            
            public Node rightMost() {
                if (right == null) return this;
                return right.rightMost();
            }
        };
    }
    
    /**
     * Your MedianFinder object will be instantiated and called as such:
     * MedianFinder obj = new MedianFinder();
     * obj.addNum(num);
     * double param_2 = obj.findMedian();
     */
    

      

    永远渴望,大智若愚(stay hungry, stay foolish)
  • 相关阅读:
    openresty开发系列12--lua介绍及常用数据类型简介
    openresty开发系列11--openresty的api入门
    SSD基本工作原理
    SSD 为什么顺序写比随机写性能更好?
    df看到的文件系统容量跟parted看到的分区容量差别较大的解决方法
    DPDK无法分出连续大页面(contiguous hugepages)的几个解决方法
    How to use, monitor, and disable transparent hugepages in Red Hat Enterprise Linux 6
    Examining Huge Pages or Transparent Huge Pages performance
    Notes of O_DIRECT flag
    leveldb
  • 原文地址:https://www.cnblogs.com/h-hkai/p/10134459.html
Copyright © 2011-2022 走看看