摘要:最大堆存的是到目前為止較小的那一半數(shù),最小堆存的是到目前為止較大的那一半數(shù),這樣中位數(shù)只有可能是堆頂或者堆頂兩個數(shù)的均值。我們將新數(shù)加入堆后,要保證兩個堆的大小之差不超過。最大堆堆頂大于新數(shù)時,說明新數(shù)將處在所有數(shù)的下半部分。
Data Stream Median 最新更新:https://yanjia.me/zh/2019/02/...
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.最大最小堆 復(fù)雜度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
時間 O(NlogN) 空間 O(N)
思路維護一個最大堆,一個最小堆。最大堆存的是到目前為止較小的那一半數(shù),最小堆存的是到目前為止較大的那一半數(shù),這樣中位數(shù)只有可能是堆頂或者堆頂兩個數(shù)的均值。而維護兩個堆的技巧在于判斷堆頂數(shù)和新來的數(shù)的大小關(guān)系,還有兩個堆的大小關(guān)系。我們將新數(shù)加入堆后,要保證兩個堆的大小之差不超過1。先判斷堆頂數(shù)和新數(shù)的大小關(guān)系,有如下三種情況:最小堆堆頂小于新數(shù)時,說明新數(shù)在所有數(shù)的上半部分。最小堆堆頂大于新數(shù),但最大堆堆頂小于新數(shù)時,說明新數(shù)將處在最小堆堆頂或最大堆堆頂,也就是一半的位置。最大堆堆頂大于新數(shù)時,說明新數(shù)將處在所有數(shù)的下半部分。再判斷兩個堆的大小關(guān)系,如果新數(shù)不在中間,那目標堆不大于另一個堆時,將新數(shù)加入目標堆,否則將目標堆的堆頂加入另一個堆,再把新數(shù)加入目標堆。如果新數(shù)在中間,那加到大小較小的那個堆就行了(一樣大的話隨便,代碼中是加入最大堆)。這樣,每次新加進來一個數(shù)以后,如果兩個堆一樣大,則中位數(shù)是兩個堆頂?shù)木担駝t中位數(shù)是較大的那個堆的堆頂。
注意Java中實現(xiàn)最大堆是在初始化優(yōu)先隊列時加入一個自定義的Comparator,默認初始堆大小是11。Comparator實現(xiàn)compare方法時,用arg1 - arg0來表示大的值在前面
代碼Leetcode
class MedianFinder { PriorityQueuemaxheap; PriorityQueue minheap; public MedianFinder(){ // 新建最大堆 maxheap = new PriorityQueue (11, new Comparator (){ public int compare(Integer i1, Integer i2){ return i2 - i1; } }); // 新建最小堆 minheap = new PriorityQueue (); } // Adds a number into the data structure. public void addNum(int num) { // 如果最大堆為空,或者該數(shù)小于最大堆堆頂,則加入最大堆 if(maxheap.size() == 0 || num <= maxheap.peek()){ // 如果最大堆大小超過最小堆,則要平衡一下 if(maxheap.size() > minheap.size()){ minheap.offer(maxheap.poll()); } maxheap.offer(num); // 數(shù)字大于最小堆堆頂,加入最小堆的情況 } else if (minheap.size() == 0 || num > minheap.peek()){ if(minheap.size() > maxheap.size()){ maxheap.offer(minheap.poll()); } minheap.offer(num); // 數(shù)字在兩個堆頂之間的情況 } else { if(maxheap.size() <= minheap.size()){ maxheap.offer(num); } else { minheap.offer(num); } } } // Returns the median of current data stream public double findMedian() { // 返回大小較大的那個堆堆頂,如果大小一樣說明是偶數(shù)個,則返回堆頂均值 if(maxheap.size() > minheap.size()){ return maxheap.peek(); } else if (maxheap.size() < minheap.size()){ return minheap.peek(); } else if (maxheap.isEmpty() && minheap.isEmpty()){ return 0; } else { return (maxheap.peek() + minheap.peek()) / 2.0; } } };
簡潔版
class MedianFinder { PriorityQueuemaxheap = new PriorityQueue (); PriorityQueue minheap = new PriorityQueue (Collections.reverseOrder()); // Adds a number into the data structure. public void addNum(int num) { maxheap.offer(num); minheap.offer(maxheap.poll()); if(maxheap.size() < minheap.size()){ maxheap.offer(minheap.poll()); } } // Returns the median of current data stream public double findMedian() { return maxheap.size() == minheap.size() ? (double)(maxheap.peek() + minheap.peek()) / 2.0 : maxheap.peek(); } };
Lintcode
public class Solution { public int[] medianII(int[] nums) { // write your code here if(nums.length <= 1) return nums; int[] res = new int[nums.length]; PriorityQueue后續(xù) Follow Upminheap = new PriorityQueue (); PriorityQueue maxheap = new PriorityQueue (11, new Comparator (){ public int compare(Integer arg0, Integer arg1) { return arg1 - arg0; } }); // 將前兩個元素先加入堆中 minheap.offer(Math.max(nums[0], nums[1])); maxheap.offer(Math.min(nums[0], nums[1])); res[0] = res[1] = Math.min(nums[0], nums[1]); for(int i = 2; i < nums.length; i++){ int mintop = minheap.peek(); int maxtop = maxheap.peek(); int curr = nums[i]; // 新數(shù)在較小的一半中 if (curr < maxtop){ if (maxheap.size() <= minheap.size()){ maxheap.offer(curr); } else { minheap.offer(maxheap.poll()); maxheap.offer(curr); } // 新數(shù)在中間 } else if (curr >= maxtop && curr <= mintop){ if (maxheap.size() <= minheap.size()){ maxheap.offer(curr); } else { minheap.offer(curr); } // 新數(shù)在較大的一半中 } else { if(minheap.size() <= maxheap.size()){ minheap.offer(curr); } else { maxheap.offer(minheap.poll()); minheap.offer(curr); } } if (maxheap.size() == minheap.size()){ res[i] = (maxheap.peek() + minheap.peek()) / 2; } else if (maxheap.size() > minheap.size()){ res[i] = maxheap.peek(); } else { res[i] = minheap.peek(); } } return res; } }
Q:如果要求第n/10個數(shù)字該怎么做?
A:改變兩個堆的大小比例,當(dāng)求n/2即中位數(shù)時,兩個堆是一樣大的。而n/10時,說明有n/10個數(shù)小于目標數(shù),9n/10個數(shù)大于目標數(shù)。所以我們保證最小堆是最大堆的9倍大小就行了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/64495.html
摘要:思路和代碼這里采用了兩個優(yōu)先隊列來實現(xiàn)。一個優(yōu)先隊列用來存儲字符流中較小的一半,另一個用來存儲字符流中數(shù)值較大的一半。這樣當(dāng)需要獲取當(dāng)前中位數(shù)時,就可以根據(jù)當(dāng)前的數(shù)值個數(shù)選擇一個或是兩個數(shù)的平均值。 題目要求 Median is the middle value in an ordered integer list. If the size of the list is even, t...
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. Examp...
摘要:建立兩個堆,一個堆就是本身,也就是一個最小堆另一個要寫一個,使之成為一個最大堆。我們把遍歷過的數(shù)組元素對半分到兩個堆里,更大的數(shù)放在最小堆,較小的數(shù)放在最大堆。同時,確保最大堆的比最小堆大,才能從最大堆的頂端返回。 Problem Numbers keep coming, return the median of numbers at every time a new number a...
摘要:難度為這個題目描述很清晰給出兩個排序好的數(shù)組求這兩個數(shù)組的中位數(shù)在解這個題的過程中會碰到以下的問題先合起來重新排序是不可行的時間復(fù)雜度太高為先歸并排序也是不可行的時間復(fù)雜度為用類似桶排的方法時間復(fù)雜度為不可行可能會碰到多種全部大于或全部小于 There are two sorted arrays nums1 and nums2 of size m and n respectively...
摘要:復(fù)雜度思路因為要找中位數(shù),又是在兩個的數(shù)組里面。所以考慮用二分法。二分法經(jīng)常適合的接下來考慮如何二分。然后對和進行比較,記為和。所以為了縮小搜索范圍,我們可以扔掉這些數(shù),在的剩下來的數(shù)中和的數(shù)組中接著找。說明中沒有個數(shù)可以尋找。 Leetcode[4] Median of two sorted arrays There are two sorted arrays nums1 and n...
閱讀 955·2023-04-25 23:50
閱讀 1954·2021-11-19 09:40
閱讀 598·2019-08-30 13:50
閱讀 2727·2019-08-29 17:11
閱讀 1041·2019-08-29 16:37
閱讀 2986·2019-08-29 12:54
閱讀 2792·2019-08-28 18:17
閱讀 2636·2019-08-26 16:55