leetcode 295 find median from data stream 找到資料流中的中位數
阿新 • • 發佈:2018-11-15
思路:
維護一個大根堆和一個小根堆,大根堆中放的是小數,小根堆中放的是大樹,這樣中位數就在大根堆和小根堆中堆頂中間作用
怎麼理解呢,試想最簡單的查詢方法是什麼,是排序,然後找到中位數,複雜度是O(N^2)
我們現在想象一下,中位數不就是排序後前一半數和後一半數中間的數嗎。那我們現在不排序,使用堆,程式碼中用優先順序隊列表示。我們大根堆放小數,大根堆堆頂就是小數中最大的數;小根堆放大樹,小根堆堆頂是大數中最小的數。那麼中位數不就是兩個堆頂中間產生嗎,要麼是前面那個數(大根堆堆頂,當然前提是均衡),要麼是平均數(大根堆小根堆堆頂平均數)
下面java程式碼
class MedianFinder { PriorityQueue <Integer> minHeap; PriorityQueue <Integer> maxHeap; /** initialize your data structure here. */ public MedianFinder() { this.minHeap= new PriorityQueue <>(); this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() { public int compare(Integer o1,Integer o2){ return o2-o1; } }); } public void addNum(int num) { //小根堆中的堆頂大於大根堆中的數 if(num<findMedian()){ //當前加入的數比中位數小,應該放前面那個大根堆中去 maxHeap.add(num); } else{ minHeap.add(num); } //設定是不允許大堆數目比小堆數目多 if(maxHeap.size()>minHeap.size()){ minHeap.add(maxHeap.poll()); } //設定允許小堆數目比大堆數目最多多1個結點 if(minHeap.size()-maxHeap.size()>1){ maxHeap.add(minHeap.poll()); } } public double findMedian() { if(maxHeap.isEmpty()&&minHeap.isEmpty()) return 0; if(maxHeap.size()==minHeap.size()) return 1.0*(maxHeap.peek()+minHeap.peek())/2.0; else return minHeap.peek();//這一個就是說我始終在小根堆裡面多放一個數,如果個數為奇數 } } /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder obj = new MedianFinder(); * obj.addNum(num); * double param_2 = obj.findMedian(); */
注意,兄弟們
程式碼中findMedian()後面的return 為什麼是返回小根堆堆頂呢???
因為設定的是在addNum中,就是要小堆始終比大堆最多多放一個,而大堆數目不允許比小堆中數多。這樣有什麼用呢,就是說,中位數要麼是平均數(倆堆數目相等),要麼是小堆中堆頂(奇數個數,小堆多放一個,你說中位數在哪裡)
那有人問了,我可不可以讓大堆多放一個?那是顯而易見的可以啊
下面貼出程式碼
class MedianFinder { PriorityQueue <Integer> minHeap; PriorityQueue <Integer> maxHeap; /** initialize your data structure here. */ public MedianFinder() { this.minHeap= new PriorityQueue <>(); this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() { public int compare(Integer o1,Integer o2){ return o2-o1; } }); } public void addNum(int num) { //小根堆中的堆頂大於大根堆中的數 if(num<findMedian()){ //當前加入的數比中位數小,應該放前面那個大根堆中去 maxHeap.add(num); } else{ minHeap.add(num); } //設定是不允許大堆數目比小堆數目多 if(maxHeap.size()-minHeap.size()>1){ minHeap.add(maxHeap.poll()); } //設定允許小堆數目比大堆數目最多多1個結點 if(minHeap.size()-maxHeap.size()>0){ maxHeap.add(minHeap.poll()); } } public double findMedian() { if(maxHeap.isEmpty()&&minHeap.isEmpty()) return 0; if(maxHeap.size()==minHeap.size()) return 1.0*(maxHeap.peek()+minHeap.peek())/2.0; else return maxHeap.peek();//這一個就是說我始終在小根堆裡面多放一個數,如果個數為奇數 } } /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder obj = new MedianFinder(); * obj.addNum(num); * double param_2 = obj.findMedian(); */
注意到了嗎,我只改了引數罷了,其他都沒動