从运行流中无限多个元素的数组返回最大k个元素的最优算法

Aja*_*aur 7 arrays algorithm stream data-structures

我有一个正在运行的整数流,如何在任何时间点从该流中获取最大的k个元素.

ami*_*mit 16

最简单的解决办法是将填充最小堆大小k.

首先,使用第一个k元素填充堆.

接下来,对于流中的每个元素 - 检查它是否大于堆的头部,如果是 - 弹出当前头部,然后插入新元素.

在流中的任何时刻 - 堆都包含最大的k元素.

该算法是O(nlogk),n到目前为止在流中遇到的元素数量.


另一种解决方案,在某些情况下,在渐近复杂性方面稍微复杂但理论上更好,是保持2k元素数组.

首先,加载前2k个元素.
运行选择算法,找到最高的算法k.丢弃其余的,此时你只剩k下数组中的元素.
现在,再次使用下一个k元素填充数组,然后重复.

在每个点,数组包含k最大的元素,以及最多k不是最大的元素.您可以为此阵列上的每个查询运行选择算法.

运行时分析:

维护阵列:每个选择算法都是O(2k) = O(k).每个k元素都会执行一次,因此n/k,如果n指示到目前为止看到的元素数量,则会给出我们O(n/k * 2k) = O(n).

另外,每个查询是O(k),如果查询的数量是Q,这给我们O(n + Q*k)运行时.

为了使这个解决方案更有效,我们需要 Q*k < nlogk

Q*k < nlogk
Q < n/k * logk
Run Code Online (Sandbox Code Playgroud)

因此,如果如上所述限制查询的数量,则该解决方案在渐近复杂度方面可能更有效.


实际上,通常使用min-heap解决方案来获得top k,至少在我看到它需要的时候.