@@ -203,6 +203,10 @@ func (h *mh) remove(i int) *viPair { return heap.Remove(h, i).(*viPair) }
203
203
// https://codeforces.com/problemset/problem/796/C 1900
204
204
// https://codeforces.com/problemset/problem/2009/G2 2200
205
205
// https://codeforces.com/problemset/problem/1732/D2 2400 简化版懒删除堆
206
+ func newLazyHeap () * lazyHeap {
207
+ return & lazyHeap {removeCnt : map [int ]int {}}
208
+ }
209
+
206
210
type lazyHeap struct {
207
211
sort.IntSlice
208
212
removeCnt map [int ]int
@@ -241,6 +245,58 @@ func (h *lazyHeap) pushPop(v int) int {
241
245
return v
242
246
}
243
247
248
+ // 滑动窗口中位数 / 距离和
249
+ // LC480 https://leetcode.cn/problems/sliding-window-median/
250
+ // LC3505 https://leetcode.cn/problems/minimum-operations-to-make-elements-within-k-subarrays-equal/
251
+ func medianSlidingWindow (nums []int , k int ) []float64 {
252
+ ans := make ([]float64 , len (nums )- k + 1 )
253
+ left := newLazyHeap () // 最大堆(元素取反)
254
+ right := newLazyHeap () // 最小堆
255
+
256
+ for i , in := range nums {
257
+ // 1. 进入窗口
258
+ if left .size == right .size {
259
+ left .push (- right .pushPop (in ))
260
+ } else {
261
+ right .push (- left .pushPop (- in ))
262
+ }
263
+
264
+ l := i + 1 - k
265
+ if l < 0 { // 窗口大小不足 k
266
+ continue
267
+ }
268
+
269
+ // 2. 计算答案(中位数)
270
+ if k % 2 > 0 {
271
+ ans [l ] = float64 (- left .top ())
272
+ } else {
273
+ ans [l ] = float64 (right .top ()- left .top ()) / 2
274
+ }
275
+
276
+ // 2. 计算答案(窗口元素到中位数的距离和)
277
+ median := - left .top ()
278
+ s1 := median * left .size + left .sum // sum 取反
279
+ s2 := right .sum - median * right .size
280
+ _ = s1 + s2 // 距离和
281
+
282
+ // 3. 离开窗口
283
+ out := nums [l ]
284
+ if out <= - left .top () {
285
+ left .remove (- out )
286
+ if left .size < right .size {
287
+ left .push (- right .pop ()) // 平衡两个堆的大小
288
+ }
289
+ } else {
290
+ right .remove (out )
291
+ if left .size > right .size + 1 {
292
+ right .push (- left .pop ()) // 平衡两个堆的大小
293
+ }
294
+ }
295
+ }
296
+
297
+ return ans
298
+ }
299
+
244
300
// 对顶堆:滑动窗口前 k 小元素和
245
301
// 保证 1 <= k <= windowSize <= n
246
302
// 返回数组 kthSum,其中 kthSum[i] 为 a[i:i+windowSize] 的前 k 小元素和
@@ -329,7 +385,6 @@ func (h *kthHeap) balance(k int) {
329
385
// 其它题目
330
386
// 求前缀/后缀的最小的 k 个元素和(k 固定)https://www.luogu.com.cn/problem/P4952 https://www.luogu.com.cn/problem/P3963
331
387
// - https://www.codechef.com/problems/OKLAMA
332
- // LC480 滑动窗口中位数 https://leetcode.cn/problems/sliding-window-median/
333
388
// https://codeforces.com/contest/1374/problem/E2 代码 https://codeforces.com/contest/1374/submission/193671570
334
389
335
390
// 如果值域比较小,可以用分桶法做到 O(n+U)
0 commit comments