在未排序的数组中查找多个子数组的中位数

时间:2018-01-09 22:33:36

标签: algorithm data-structures

假设给你一个未排序的整数数组S和一个T范围列表,返回每个范围的中位数列表。

例如,S = [3,6,1,5,0,0,1,-2],T = [[1,3],[0,5],[4,4]]。返回[5,2,0]。

是否有比在每个范围内运行Median of Medians更好的方法?我们可以以某种方式预先计算/缓存结果吗?

1 个答案:

答案 0 :(得分:4)

让我向您介绍一个名为 Wavelet Tree的有趣数据结构:

通过查看整数的位串表示并递归地将它们一分为二来构建它:

首先将整数分为具有最高有效位(MSB)0和MSB 1的整数。但是,您将MSB以原始顺序存储在位向量中。然后,对于这些整数子集中的每一个,忽略MSB并递归重复此构造以获得下一个最重要的位。

如果你重复这个到最不重要的位,你会得到一个像这样的树结构(注意索引只是为了说明,你应该只存储位向量):

wavelet tree on 462725342471306

您可以很容易地看到此数据结构的构造需要O(n log N)时间,其中n是整数,N是它们的最大值。

小波树具有很好的属性,它们同时表示原始序列以及它们的排序对应物:

  • 如果您读取最顶层的位向量,则会获得输入序列的MSB。要重建条目的下一位,您可以在查看根的左子项中的位向量(如果MSB为0)或右子项(如果MSB为1)之间切换。对于以下位,您可以递归地继续。

  • 如果从左到右读取叶节点,则会得到排序序列。

要有效地使用小波树,您需要在位向量上进行两项基本操作:

  • rank1(k)告诉你在位向量中的 k 位置之前有多少1, rank0 对于0来说是相同的< / LI>
  • select1(k)告诉你bitvector中 k th 1的索引, select0 为0s做同样的事情

请注意,有些位向量表示只需要o(n)(小o)位的额外存储空间来实现O(1)

中的这些操作

您可以按如下方式使用它们:

  • 如果您正在查看上面序列中的前7个,它有索引3.如果您现在想知道它在右子节点中有哪个索引,您只需调用 rank1(3) 在根bitvector上得到2,这正是右孩子中前7个的索引

  • 如果您在包含4544的孩子,并想知道包含46754476的父节点中第二个4(带索引2)的位置,则调用 select0(2) on父的bitvector并得到索引5.

现在如何用这个实现范围中值查询?您需要做的最重要的实现是找到 k 大小范围的中位数等同于选择 k / 2 元素。

该算法的基本思想类似于Quickselect:将元素范围平分并仅递归到包含您要查找的元素的范围内。

假设我们想要找到范围的中位数,从第二个2(包括)开始到结束在1(不包括)。 这些是7个元素,因此中值在该范围内具有等级4(第四最小元素)。 现在在该范围的开头和结尾的根位向量中使用 rank0 / 1 调用,我们在根的子节点中找到相应的范围:

WT: descent into children

如您所见,左边距(仅包含较小的元素)只有3个元素,因此具有等级4的元素必须包含在根的右子节点中。我们现在可以递归搜索该右子中具有等级4 - 3 = 1的元素。通过以递归方式递减小波树直到到达叶子,您可以因此识别每个小波树级别仅有两个秩操作(àO(1)时间)的中值,因此整个范围中值查询需要O(log N)时间,其中N是输入序列中的最大数字。

如果您想查看这些Wavelet树的实际实现,请查看实现上述bitvectors和不同WT变体的Succinct Data Structures Library (SDSL)