生活随笔
收集整理的這篇文章主要介紹了
LeetCode 480. 滑动窗口中位数(大小堆升级版+set实现)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. 題目
中位數是有序序列最中間的那個數。
如果序列的大小是偶數,則沒有最中間的數;此時中位數是最中間的兩個數的平均數。
例如:
[2,3,4],中位數是 3
[2,3],中位數是 (2 + 3) / 2 = 2.5
給你一個數組 nums,有一個大小為 k 的窗口從最左端滑動到最右端。
窗口中有 k 個數,每次窗口向右移動 1 位。
你的任務是找出每次窗口移動后得到的新窗口中元素的中位數,并輸出由它們組成的數組。
示例:
給出 nums
= [1,3,-1,-3,5,3,6,7],以及 k
= 3。窗口位置 中位數
--------------- -----
[1 3 -1] -3 5 3 6 7 11 [3 -1 -3] 5 3 6 7 -11 3 [-1 -3 5] 3 6 7 -11 3 -1 [-3 5 3] 6 7 31 3 -1 -3 [5 3 6] 7 51 3 -1 -3 5 [3 6 7] 6因此,返回該滑動窗口的中位數數組
[1,-1,-1,3,5,6]。提示:
你可以假設 k 始終有效,即:k 始終小于輸入的非空數組的元素個數。
與真實值誤差在
10 ^ -5 以內的答案將被視作正確答案。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/sliding-window-median
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
2. 解題
類似題目:
LeetCode 295. 數據流的中位數(大小堆)
LeetCode 703. 數據流中的第K大元素(優先隊列)
參考我的博客 數據結構 堆(優先隊列)
參考大小堆的思想,一個堆最多比另一個堆最多多一個元素,不再多講,請參考上面鏈接
- 關鍵要實現從堆中刪除窗口左端點,那么用 set 來當做堆就可以突破優先隊列(堆)不能刪除非堆頂元素
- 本題:小堆size = 大堆size or 小堆size = 大堆size+1
- k 為 奇數,直接返回小堆頂 set.begin()
- k 為 偶數,返回兩個堆頂的平均值
class Solution { multiset
<int> minheap
;multiset
<int,greater
<int>> maxheap
;
public:vector
<double> medianSlidingWindow(vector
<int>& nums
, int k
) {if(k
== 1) return vector
<double>(nums
.begin(), nums
.end());int n
= nums
.size(), i
= 0, j
= 0, idx
= 0;long a
, b
;vector
<double> ans(n
-k
+1);for( ; j
< k
; ++j
)maxheap_minheap_add(nums
[j
]);a
= (*maxheap
.begin()), b
= (*minheap
.begin());ans
[idx
++] = (k
&1) ? b
: (a
+b
)/2.0;for(i
= 0 ; j
< n
; ++i
,++j
){maxheap_minheap_del(nums
[i
]);maxheap_minheap_add(nums
[j
]);a
= (*maxheap
.begin()), b
= (*minheap
.begin());ans
[idx
++] = (k
&1) ? b
: (a
+b
)/2.0;}return ans
;}void maxheap_minheap_add(int x
){if(minheap
.empty())minheap
.insert(x
);else if(maxheap
.size() == minheap
.size()){if(x
>= *maxheap
.begin())minheap
.insert(x
);else{minheap
.insert(*maxheap
.begin());maxheap
.erase(maxheap
.begin());maxheap
.insert(x
);}}else if(maxheap
.size() < minheap
.size()){if(x
<= *minheap
.begin())maxheap
.insert(x
);else{maxheap
.insert(*minheap
.begin());minheap
.erase(minheap
.begin());minheap
.insert(x
);}}}void maxheap_minheap_del(int x
){if(maxheap
.size() < minheap
.size()){auto it
= minheap
.find(x
);if(it
!= minheap
.end())minheap
.erase(it
);else{maxheap
.erase(maxheap
.find(x
));maxheap
.insert(*minheap
.begin());minheap
.erase(minheap
.begin());}}else if(maxheap
.size() == minheap
.size()){auto it
= maxheap
.find(x
);if(it
!= maxheap
.end())maxheap
.erase(it
);else{minheap
.erase(minheap
.find(x
));minheap
.insert(*maxheap
.begin());maxheap
.erase(maxheap
.begin());}}}
};
108 ms 18.9 MB
總結
以上是生活随笔為你收集整理的LeetCode 480. 滑动窗口中位数(大小堆升级版+set实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。