480. Sliding Window Median
題目網址:https://leetcode.cn/problems/sliding-window-median
題意:中位數是指有序 array 裡中間的數。若 array 長度偶數, 則中位數是中間兩數的平均值。
arr = [2,3,4], 則中位數 =3arr = [2,3], 則中位數 =(2+3) / 2 = 2.5給一整數 array
nums和一整數k, 有一長度為k的 sliding window 從nums最左端滑到最右端, 每次向右移動一位, 求每次移動 sliding window 後得到的中位數, 並返回由這些中位數所組成的 array。

Solution:
想法:利用 Heap, 類似 295. Find Median from Data Stream, 使用兩個 heap + 延遲刪除, 我們定義平衡:
- 滿足
smaller.size() - larger.size() ≤ 1也就是說
smaller的元素個數要麼比larger多一, 要麼相同這樣設計的好處在於:
- 當
k為偶數時, 各自的 top 之平均值即為中位數- 當
k為奇數時, 則smaller.top()即為中位數每次移動 window 的操作:
- 在每次移動 sliding window 前都為平衡的, 也就是
smaller.size() - larger.size() ≤ 1- 設置
balance = 0, 用來記錄該次移動 window 中,smaller和larger元素個數的差值- 刪除 window 左側的元素
- 由於 heap 沒辦法刪除指定的元素
val, 因此先欠下這個帳, 等到val出現在heap.top()時, 再進行刪除。delay紀錄val欠賬的次數, 因此++delay[val]- 新增 window 右側的元素
- 若
nums[i] <= smaller.top(), 則把nums[i]放到smalller中, 然後++balance- 否則, 把
nums[i]放到larger中, 然後-balance- 經過上述刪除/新增的操作, 此時
balance為2、0、2這三種情況之一:
2:本次移動中刪除的元素是在smaller中的, 且新增的元素是larger0:
- 本次移動中刪除的元素是在
smaller中的, 且新增的元素是在smaller- 本次移動中刪除的元素是在
larger中的, 且新增的元素是在larger2:本次移動中刪除的元素是在larger中的, 且新增的元素是smaller- 我們需要進行調整, 使
balance = 0, 也就smaller.size() - larger.size() ≤ 1:
- 若
balance== -2, 則把larger.top()給 pop 掉, 並將其 push 到smaller中- 若
balance== 0, 則不需調整- 若
balance == 2, 則把smaller.top()給 pop 掉, 並將其 push 到larger中- 調整完後, 接著要計算中位數。但在計算中位數前, 必須先把欠的帳給還了, 避免那些應該刪除的數影響到中位數的計算
- 分別檢查兩邊的 heap, 若
heap.top()欠著債, 則將其 pop 掉, 直到heap.top()沒有欠債為止- 若那些應刪除的數不為
heap.top()該怎麼辦 ? 由於計算中位數的時候只與heap.top()有關, 至於那些不為heap.top()但欠著債的, 就讓他們欠著吧, 等他們成為heap.top()的時候再 pop 掉就行了- 最後, 計算中位數
class Solution { |
- time:$O(n \cdot log(n))$ ➔ 每次 insert / delete 皆須 $log(n)$, worse case:應被刪除的數皆不為 top, 導致
smaller + larger為n個數 - space:$O(n)$ ➔
smaller + larger和delay, 長度皆不超過n
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 Zako's Blog!
評論