支持基于范围的最常见元素查询的数据结构

时间:2010-10-06 16:25:11

标签: algorithm data-structures

我正在寻找一种数据结构,我可以在给定的可变范围内找到最常出现的数字(在一组数字中)。

让我们考虑以下基于1的数组:

1 2 3 1 1 3 3 3 3 1 1 1 1

如果我查询范围(1,4),数据结构必须重新调整1,这将发生两次。 其他几个例子:

(1,13)= 1

(4,9)= 3

(2,2)= 2

(1,3)= 1(所有1,2,3都出现一次,所以返回第一个/最小的一个。此时不那么重要)

我搜索过,但找不到类似的东西。我正在寻找(理想情况下)具有最小空间要求,快速预处理和/或查询复杂性的数据结构。

提前致谢!

2 个答案:

答案 0 :(得分:1)

设N是数组的大小,M是该数组中不同值的数量。

我正在考虑两个复杂性:预处理和查询大小为n的区间,每个区间必须是空间和时间的。

<小时/> 解决方案1:

  • 空间:O(1)和O(M)
  • 时间:O(1)和O(n + M)

没有预处理,我们会查看间隔的所有值并找到最常用的值。

<小时/> 解决方案2:

  • 空间:O(M * N)和O(1)
  • 时间:O(M * N)和O(min(n,M))

对于数组的每个位置,我们有一个累积数组,它给出了每个值x,x在该位置之前的数组中的x次。

给定一个区间,我们只需要每个x减去2个值来找到该区间中的x个数。我们迭代每个x并找到最大值。如果n < M我们遍历区间的每个值,否则我们迭代x的所有可能值。

<小时/> 解决方案3:

  • 空间:O(N)和O(1)
  • 时间:O(N)和O(min(n,M)* log(n))

对于每个值x,构建数组中存在x的所有位置的二进制堆。堆中的键是位置,但是您还存储了此位置和数组开头之间的x总数。

给定一个区间,我们只需要每个x减去2个值来找到该区间中的x个数:在O(log(N))中我们可以要求x的堆在开始之前找到两个位置/间隔结束并减去数字。基本上它比直方图需要更少的空间,但现在查询在O(log(N))中。

答案 1 :(得分:0)

您可以创建二进制分区树,其中每个节点表示{value - &gt;的直方图。对于给定范围,有两个子节点,表示范围的上半部分和下半部分。

然后查询只是递归地将少量这些直方图加在一起以覆盖所需的范围,并扫描结果直方图一次以找到最高发生次数。

有用的优化包括:

  • 在将直方图添加到一起时,使用具有可变频率计数的直方图作为“累加器”
  • 一旦达到一定的大小(可能是小于可能值M总数的范围)并且直接计算数字,就停止使用预先计算的直方图。这是一个时间/空间权衡,我认为这将在很多时候得到回报。
  • 如果您有固定的少量可能值,请使用数组而不是地图来存储每个节点的频率计数

更新:我对算法复杂性的思考,假设在整个范围内有少量可能的值M和总共N个值:

  • 预处理 O(N log N) - 基本上您需要遍历完整列表并构建二叉树,为每个M元素构建一个节点,以便分摊每个节点的开销< / LI>
  • 查询 O(M log N) - 基本上将每个大小为M的O(log N)直方图相加,再加上计算范围任一侧的O(M)值
  • 空间要求 O(N) - 约。尺寸为M的2N / M直方图.2因子是底部N / M直方图,下一级0.5N / M直方图,第三级0.25N / M等的总和...