维护定长窗口内前K大/小值

维护定长窗口内前K大/小值

K=1

当K=1的时候,就是我们非常熟悉的滑动窗口问题,用一个单调队列来维护窗口最值即可。

K>1

K > 1的时候,单调队列就不管用了,因为他令元素出队的操作,会丢失部分信息。
例如,维护前3大的元素:
11 12 10 5
我们会创建一个递减的单调队列,但是12入队的时候11就被干掉了,它本该是被输出的答案之一。

solutions

1. 堆

我们可以用小根堆来存储前K大值,或者利用大根堆来存储前K小值,然后再通过延迟删除的方式来维护序列。

解释一下堆的部分:
比如我们要维护前K大,那我们就维护一个大小为K的小根堆,那么堆顶就表示最大的K个数当中,最小的那个
当堆内元素数量小于K,直接入栈;
否则,比较一下堆顶和新元素,如果堆顶小于新元素,就出队然后放进新元素。

而延迟删除指的是,当我们的窗口左端点离开下标idx的时候,我们需要把nums[idx]出栈,我们并不立刻出栈(因为优先队列不支持下标随机访问),而是建立一个哈希表,把idx放进去,在查询的时候,如果堆顶是被标记过,就一直出栈。

上面的做法看起来很棒,但是如果我们要用小根堆维护前K大元素,我们就必须严格控制堆内元素个数为K,如果我们延迟删除,就会有无效元素占着堆的空间,导致我们很难控制堆的大小 ……

这时候,我们与其绞尽脑汁去思考怎么优化延迟删除策略,不如直接手写一个支持随机访问的堆,这样就不用担心这个大小控制了,还能省去哈希表的空间。

2. 平衡树

可以直接用STL里面的set实现,控制set的大小为k,里面的元素就是我们要求的答案。

posted @ 2025-03-04 21:54  Gold_stein  阅读(47)  评论(0)    收藏  举报