【问题标题】:Efficient way to find the a-th to b-th smallest elements across k arrays在 k 个数组中找到第 a 到第 b 个最小元素的有效方法
【发布时间】:2018-11-18 00:05:57
【问题描述】:

我最近接受了一家社交媒体公司的采访,我被问到以下问题。

k 个长度为 m 的未排序数组。目标是在给定 a b m。在后续问题中,将“未排序的数组”更改为跨 MySQL 数据库中不同表的列,可以使用哪些高效的数据结构以及相应的检索算法是什么。

我想出了两种可能的解决方案:

第一:暴力破解:

  1. 首先使用快速选择找到每个数组的第 b 个最小元素。
  2. 然后找到小于每个数组的b-th元素的元素,存入一个大小为k * b B-tree C。
  3. 然后在C中找到a-thb-th个最小的元素。

第一步使用快速选择找到b-th个最小元素,平均时间是从O(km)O(km * log(m)) 总计。第 2 步的时间复杂度为 O(km)。最后一步是找到 Ca-thb-th 最小元素之间的元素,取 O((ba)日志(kb))。所以总共需要 O(km)O(km * log(m)) + O((ba)log(kb )) 在时间上,在空间上 O(kb)

第二:递归弹出最小的元素

对于每个循环,做

  1. 找到所有k个数组的最小元素,存储在B-treeC
  2. C中找到最小的元素,并从C中弹出这个元素,并从它来的数组中弹出。
  3. 重复直到弹出a-1个数字,然后转到4
  4. 将值从 a 存储到 b,同时重复 1 到 2

所以计算复杂度是O(k * log(k)) + O(b * log(k) ),空间复杂度为O(max( k , ba ))。这似乎是最小的空间复杂度。

有哪些更有效的方法来做到这一点?尤其是快速选择最坏的情况是O(n^2),这似乎太大了,而对于b = m/2正好在中位数O(kb ) 在空间或 O(b * log(k)) 在时间被认为太大。对于 MySQL 数据库,我建议使用 B-tree,它在解决方案 1 中提供快速排名选择,同时在空间和时间上仍然存在 O(kb)k 查询数据库。在解决方案 2 中,据说对 MySQL 数据库的 b 查询太大并且 B-tree 插入是 O(log(m)) 其中 m 可能非常大.

【问题讨论】:

  • 你有这份工作吗?

标签: python mysql algorithm sorting time-complexity


【解决方案1】:

一种简单的方法是创建一个大小为 b 的最大堆。然后运行这段代码:

for arr in arrays // process each of the k arrays in turn
    for i = 0 to length(k)-1
        if heap.count < b
            heap.push(arr[i])
        else if (arr[i] < heap.peek())
            heap.pop()
            heap.push(arr[i])

这里的想法是用第一个 b 项填充一个最大堆。然后,对于每个其他项,如果它小于堆上的最大项,则使用新项删除堆上最大的项。

当你处理完所有km项后,最小的b项在堆上,因为它是最大堆,第一个ba 项将是所有 k 数组中的 ath 到 bth 项。

// all items have been processed, take the first *b - a* items from the max heap
for i = 0 to (b-a-1)
   result[i] = heap.pop()

最坏的情况是第一个循环为 O(km log b),第二个循环为 O(b log b),使用 O(b) 额外内存。

如果您被允许销毁源数组,您可以编写一个自定义快速选择,将 k 数组索引为单个数组。那将是 O(km),使用 O(k) 额外内存作为间接索引。缺点是索引代码会慢一些。而且,当然,这些项目会在数组之间移动。而且您可能需要 O(b) 额外的内存来存储返回值。渐近地它比我原来的选择更有效。它是否会跑得更快完全是另一个问题。

另一种可能性。在每个 k 数组上运行 build-heap 方法。那将是O(公里)。然后进行合并以选择第一个 b 项。合并需要:

  • O(log m) 从源数组中删除每个项目
  • O(log b) 将每个项目添加到合并堆中
  • O(log b) 从合并堆中删除每个项目

第二步是 O(b * (log m + log b + log b))。

这给出了 O(km + b * (log m + log b + log b)) 的总和,你会使用 O(b) 额外的内存。这是否会比最初的建议更快是值得怀疑的。这取决于bm之间的关系。 b 的值越大,越不可能更快。而且代码写起来要复杂得多。

【讨论】:

    猜你喜欢
    • 2012-10-22
    • 2015-01-15
    • 2022-01-04
    • 2019-08-13
    • 2017-03-04
    • 1970-01-01
    • 2021-09-07
    • 2018-11-12
    相关资源
    最近更新 更多