【问题标题】:Efficiently find order statistics of unsorted list prefixes?有效地查找未排序列表前缀的顺序统计信息?
【发布时间】:2013-03-12 01:46:39
【问题描述】:

A 是从1n 随机排列的整数数组。

我需要至少在日志时间内随机访问第一个 j 元素中的 ith 最大元素。

到目前为止,我想出的是一个n x n 矩阵M,其中(i, j) 位置的元素是第一个j 中最大的i。这给了我恒定时间随机访问,但需要n^2 存储。

通过构造,M 按行和列排序。此外,每一列与其相邻列的差异只有一个值。

谁能建议一种方法将M 压缩到n log(n) 空间或更好,log(n) 或更好的随机访问时间?

【问题讨论】:

  • 可以给个样例输入输出吗?
  • 这是一个非常有趣的问题,我正在考虑它:)

标签: algorithm data-structures language-agnostic


【解决方案1】:

我相信你可以在 O(log(N)) 时间内执行访问,给定 O(N log(N)) 预处理时间和 O(N log(N)) 额外空间。方法如下。

您可以扩充红黑树以支持 select(i) 操作,该操作在 O(log(N)) 时间内检索等级为 i 的元素。例如,see this PDF算法简介的相应章节。

您可以以一种功能性的方式实现一棵红黑树(甚至增强为支持select(i)),这样插入操作会返回一棵新树,该树与旧树共享除 O(log(N)) 之外的所有节点树。例如,请参阅 Chris Okasaki 的 Purely Functional Data Structures

我们将构建一个纯功能增强红黑树数组T,这样树T[j] 存储A 的第一个j 元素的索引0 ... j-1,从大到小排序。

基本情况:在T[0] 创建一个只有一个节点的增强红黑树,其数据是数字 0,它是数组 A 的前 1 个元素中第 0 个最大元素的索引。

归纳步骤:对于从 1 到 N-1 的每个 j,在 T[j] 处,通过将索引为 j 的新节点纯功能插入到树 T[j-1] 中来创建一个增强的红黑树。这最多创建 O(log(j)) 个新节点;其余节点与T[j-1] 共享。这需要 O(log(j)) 时间。

构造数组T的总时间是O(N log(N)),使用的总空间也是O(N log(N))。

创建T[j-1] 后,您可以通过执行T[j-1].select(i) 来访问A 的第一个j 元素中的ith 最大元素。这需要 O(log(j)) 时间。请注意,您可以在第一次需要时懒惰地创建T[j-1]。如果A 很大,j 总是比较小,这样会节省很多时间和空间。

【讨论】:

  • 我只是想到了这个解决方案,打算在这里发布,但你打败了我。很好的答案!
【解决方案2】:

除非我理解错了,否则你只是找到一个数组的k-th order statistic,它是另一个数组的前缀。

这可以使用我认为称为“快速选择”的算法或类似的算法来完成。基本上,它就像快速排序:

  1. 随机选择一个轴
  2. 交换数组元素,使所有较小的元素都在一侧
  3. 您知道这是第 p+1 个最大元素,其中 p 是较小数组元素的数量
  4. 如果 p+1 = k,这就是解决方案!如果 p+1 > k,在“较小的”子数组上重复。如果 p+1

在 Quickselect 和 Quicker Select 标题下有一个(很多)更好的描述 here,如果您搜索 k 阶快速排序解决方案,通常也可以在 Internet 上找到。

虽然该算法的最坏情况时间是 O(n2),如快速排序,但如果您正确选择随机枢轴,它的预期情况会好得多(也类似于快速排序)。我认为空间复杂度只是 O(n);您只需复制一份您的前缀即可完成订购。

【讨论】:

  • 看起来您需要为每个单独的 j 单独的 O(j) 空间,总计二次空间。如果你能找到一种方法来结合它,那么你就成功了。
  • 嗯,没错。备用数组的设置和拆卸将是 O(n),因此可以将其包含在时间复杂度中,并且您永远不需要同时超过 O(j) 的内存复杂度。
猜你喜欢
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
相关资源
最近更新 更多