295. Find Median from Data Stream
題目網址:https://leetcode.cn/problems/find-median-from-data-stream/
題意:中位數是指有序 array 裡中間的數。若 array 長度偶數, 則中位數是中間兩數的平均值。
arr = [2,3,4], 則中位數 =3arr = [2,3], 則中位數 =(2+3) / 2 = 2.5請實現
MedianFinderclass:
MedianFinder():初始化 MedianFindervoid addNum(int num):新增num到資料結構中double findMedian():找出目前的中位數

Solution 1:
想法:利用 Balanced BST(紅黑樹), C++ 可直接使用
multiset, 將元素 push 到 multiset 中它會自動排好序。我們用一個 iteratormid指向目前的中位數(若 multiset 中的元素個數為偶數, 則讓 mid 指向中間靠左的元素)
- 若
num加入前,set中的元素為偶數個(OOXOOO, 其中X代表mid), 則加入nums後, 分兩種情況:
- 若
nums >= *mid:OOXOOO(加入前) ➔OOXOOOO(加入後), 則要將mid往右移一位,OOXOOOO➔OOOXOOO- 若
nums < *mid:OOXOOO(加入前) ➔OOOXOOO(加入後), 則mid不需移動- 加入
num後,set中的元素變為奇數個, 因此返回mid即可- 若
num加入前,set中的元素為奇數個(OOXOO), 則加入nums後, 分兩種情況:
- 若
nums >= *mid:OOXOO(加入前) ➔OOXOOO(加入後), 則mid不需移動- 若
nums < *mid:OOXOO(加入前) ➔OOOXOO(加入後), 則要將mid往左移一位,OOOXOO➔OOXOOO- 加入
num後,set中的元素變為偶數個, 因此要返回中間兩數的平均值
class MedianFinder { |
- time:
addNum():$O(log(n))$, Balanced BST 新增元素所需的時間複雜度為 $O(h)$, 因為是 Balanced, 所以 $h = log(n)$findMedian():$O(1)$
- space:$O(n)$ ➔
set
Solution 2:
想法:利用 Heap, 使用兩個 heap 來分別記錄中間左中位數、右中位數, 因為當
set中元素為偶數時, 我們需要取得這兩個數來計算平均值
- Max Heap
smaller紀錄所有≤ 中位數的數,smaller.top()可得到所有≤ 中位數的數中最大的值, 也就是左中位數- Min Heap
larger紀錄所有> 中位數的數,larger.top()可得到所有> 中位數的數中最小的值, 也就是右中位數在新增
num時, 我們必須使兩個 heap 的長度保持平衡, 平衡的定義如下:
- 滿足
0 ≤ | smaller.size() - larger.size() | ≤ 1當兩個 heap 的長度不平衡時, 則把長度較長者的 top 給 pop 掉, 並把其 push 到另一個 heap
- 要返回中位數時, 我們比較兩個 heap 的長度
若
smaller.size() > larger.size()時, 返回smaller.top()e.g.
smaller = [1,2,3],larger = [4,5], 則中位數 =3若
larger.size() > smaller.size()時, 返回larger.top()e.g.
smaller = [1,2],larger = [3,4,5], 則中位數 =3若
smaller.size() == larger.size(), 代表set中元素個數為偶數, 返回中間兩數的平均值, 也就是(smaller.top() + larger.top()) / 2.0e.g.
smaller = [1,2,3],larger = [4,5,6], 則中位數 =(3 + 4) / 2 = 3.5
class MedianFinder { |
- time:
addNum():$O(log(n))$ 從 heap 中新增 or 刪除元素findMedian():$O(1)$
- space:$O(n)$ ➔
smaller+larger的長度不超過n
