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.

Examples: 

[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.

For example:

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

鏈接: http://leetcode.com/problems/find-median-from-data-stream/

題解:

在Data stream中找到median。這道題是Heap的經典應用,需要同時維護一個最大堆和一個最小堆, 最大堆和最小堆的size <= 當前數字count / 2。在學習heap數據結構的時候一般都會講到這一題,很經典。

Time Complexity: addNum - O(logn)  , findMedian - O(1),  Space Complexity - O(n)

class MedianFinder {
    private PriorityQueue<Integer> maxOrientedHeap;
    private PriorityQueue<Integer> minOrientedHeap;
    
    public MedianFinder() {
        this.minOrientedHeap = new PriorityQueue<Integer>();
        this.maxOrientedHeap = new PriorityQueue<Integer>(10, new Comparator<Integer>() {
                public int compare(Integer i1, Integer i2) {
                    return i2 - i1;
                }
            });
    }
    // Adds a number into the data structure.
    public void addNum(int num) {
        maxOrientedHeap.add(num);               // O(logn)
        minOrientedHeap.add(maxOrientedHeap.poll());               // O(logn)
        if(maxOrientedHeap.size() < minOrientedHeap.size()) {
            maxOrientedHeap.add(minOrientedHeap.poll());        //O(logn)
        }
    }

    // Returns the median of current data stream
    public double findMedian() {                    // O(1)
        if(maxOrientedHeap.size() == minOrientedHeap.size())
            return (maxOrientedHeap.peek() + minOrientedHeap.peek()) / 2.0;
        else
            return maxOrientedHeap.peek();
    }
};

// Your MedianFinder object will be instantiated and called as such:
// MedianFinder mf = new MedianFinder();
// mf.addNum(1);
// mf.findMedian();

 

二刷:

依然使用了兩個PriorityQueue,一個maxPQ,一個minPQ。最小堆中存的是較大的一半數據,最大堆中存的是較小的一半數據。當傳入數字計數為奇數是,我們直接返回minPQ.peek(), 否則我們返回 (maxPQ.peek() + minPQ.peek()) / 2.0。 這樣做速度不是很理想,也許是maxPQ的lambda表達式構建出的comparator沒有得到優化,換成普通的comparator速度至少快一倍。也可以用Collections.reverseOrder()來作為maxPQ的comparator。

 

見到有些朋友用了構建BST來做,這樣減少了幾次O(logn)的操作,速度會更快,以后在研究。

 

Java:    

Min and Max Heap

Time Complexity: addNum - O(logn)  , findMedian - O(1),  Space Complexity - O(n)

class MedianFinder {
    Queue<Integer> minPQ = new PriorityQueue<>();
    Queue<Integer> maxPQ = new PriorityQueue<>(10, (Integer i1, Integer i2) -> i2 - i1);
    // Adds a number into the data structure.
    public void addNum(int num) {
        minPQ.offer(num);
        maxPQ.offer(minPQ.poll());
        if (minPQ.size() < maxPQ.size()) minPQ.offer(maxPQ.poll());
    }

    // Returns the median of current data stream
    public double findMedian() {
        if (minPQ.size() == maxPQ.size()) return (minPQ.peek() + maxPQ.peek()) / 2.0;
        return minPQ.peek();
    }
};

// Your MedianFinder object will be instantiated and called as such:
// MedianFinder mf = new MedianFinder();
// mf.addNum(1);
// mf.findMedian();

 

 

Reference:

https://leetcode.com/discuss/65107/share-my-java-solution-logn-to-insert-o-1-to-query

https://leetcode.com/discuss/64850/short-simple-java-c-python-o-log-n-o-1

https://leetcode.com/discuss/64811/easy-to-understand-double-heap-solution-in-java

https://leetcode.com/discuss/64910/very-short-o-log-n-o-1

https://leetcode.com/discuss/64842/32ms-easy-to-understand-java-solution

https://leetcode.com/discuss/68290/simple-java-solution-with-2-heaps-and-explanation

https://leetcode.com/discuss/64852/java-python-two-heap-solution-o-log-n-add-o-1-find

https://leetcode.com/discuss/94126/18ms-beats-100%25-java-solution-with-bst


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM