[劍指offer]------64 數據流中的中位數

  • 溫馨 小提示:如果代碼看不懂,不妨拿出紙和筆,找幾個例子,多走幾遍程序,

                   再搜索一下相關的博客,慢慢的就加深理解了。


題目:

        如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。

 

代碼思路:

        我們可以將數據排序後分爲兩部分,左邊部分的數據總是比右邊的數據小。那麼,我們就可以用最大堆和最小堆來裝載這些數據:

  • 最大堆裝左邊的數據,取出堆頂(最大的數)的時間複雜度是O(1)
  • 最小堆裝右邊的數據,同樣,取出堆頂(最小的數)的時間複雜度是O(1)

        從數據流中拿到一個數後,先按順序插入堆中:如果左邊的最大堆是否爲空或者該數小於等於最大堆頂的數,則把它插入最大堆,否則插入最小堆。然後,我們要保證左邊的最大堆的size等於右邊的最小堆的size或者最大堆的size比最小堆的size大1。
        要獲取中位數的話,直接判斷最大堆和最小堆的size,如果相等,則分別取出兩個堆的堆頂除以2得到中位數,不然,就是最大堆的size要比最小堆的size大,這時直接取出最大堆的堆頂就是我們要的中位數。

 

解題代碼:

import java.util.PriorityQueue;
import java.util.Comparator;
public class Solution {
    // 最小堆(右)
    private PriorityQueue<Integer> rHeap = new PriorityQueue<>(); 
    // 最大堆(左)
    private PriorityQueue<Integer> lHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
    // 保證lHeap.size()>=rHeap.size()
    public void Insert(Integer num) {
        // 先按大小插入,再調整
        if(lHeap.isEmpty() || num <= lHeap.peek())
            lHeap.offer(num);
        else
            rHeap.offer(num);

        if(lHeap.size() < rHeap.size()){
            lHeap.offer(rHeap.peek());
            rHeap.poll();
        }else if(lHeap.size() - rHeap.size() == 2){
            rHeap.offer(lHeap.peek());
            lHeap.poll();
        }
    }
    public Double GetMedian() {
        if(lHeap.size() > rHeap.size())
            return new Double(lHeap.peek());
        else
            return new Double(lHeap.peek() + rHeap.peek())/2;
    }
}

 

參考文章:

https://www.weiweiblog.cn/getmedian/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章