查找最大和n / 3个最大元素的实现

时间:2018-11-09 20:35:59

标签: algorithm

假设您一直都在获取数字,而您不知道开始会出现多少个数字。在任何时候,我都希望能够立即n/3输出最大的数字和n的最大数字(其中(in O(1))是到目前为止输入的数字的数量)。输入新号码的最长时间为O(log(n))

实现此目标的最佳方法是什么?

1 个答案:

答案 0 :(得分:3)

您可以用两个heaps来实现它:最小堆(A)和最大堆(B)。

这个想法是将 n / 3 最大值存储在A中,其余的存储在B中,这样B中的最大值就是 n / 3 最大值(从零开始计数)。假设在 n 不是三的倍数的情况下将 n / 3 截断,并且结果值是从零开始的(n/3 == 0表示最大值也是 n / 3 的最大元素),这意味着必须保持以下不变性:

A.size == floor((A.size + B.size)/3)

...归结为:

0 <= B.size - 2*A.size < 3 

上述条件可能会有所不同,具体取决于解释 n / 3 元素是什么(是从0开始,从1开始,四舍五入,被舍入等),还有一些如果集合中的元素少于3个,则可能需要特别注意,具体取决于该定义。

要添加值 v ,您首先要确定它属于哪个堆。如果它小于当前的 n / 3 th 最大值(B中的最大值),则它属于B,否则属于A。在添加之后,不变性可能会被破坏,必须通过从任一堆中提取一个值并将其添加到另一堆中来恢复。

更正式地添加了 v ,如下所示:

if v < B.peek():
    B.add(v)
    if B.size - 2*A.size >= 3:
        A.add(B.pull())
else:
    A.add(v)
    if B.size - 2*A.size < 0:
        B.add(A.pull())

获得 n / 3 th 最大值的实现是:

B.peek()

以上所用方法的时间复杂度为:

  • 大小: O(1)
  • 偷看: O(1)
  • 拉: O(logn)
  • 添加: O(登录)

要保持整体最大值是一件容易的事。堆仅用于跟踪 n / 3 th 最大值。