找到k个数组中第a个到第b个最小元素的有效方法

时间:2018-06-08 01:01:31

标签: python mysql algorithm sorting time-complexity

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

k 未排序的数字长度为 m 的数组。目标是以高效且内存保守的方式在 k 数组中找到第a b 个最小元素,给定 a < b < 。在后续问题中,“未排序的数组”被更改为MySQL数据库中不同表的列,可以使用哪些可能的高效数据结构以及相应的检索算法。

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

第一:暴力:

  1. 首先使用quickselect找到每个数组的第b个最小元素。
  2. 然后找到小于每个数组的 b-th 元素的元素,并将它们存储为 k * b B-tree < EM> C 的。
  3. 然后在 C 中找到 a-th b-th 最小元素。
  4. 使用quickselect找到 b-th 最小元素的第一步,平均时间是从 O(km) O(km * log(m))总计。第2步时间复杂度为 O(km)。最后一步是在 C 中找到 a 和 b-th 最小元素之间的元素,取 O((ba)日志(KB))。所以总需要 O(km) O(km * log(m)) + O((ba)log(kb) ))及时, O(kb)在太空中。

    第二:递归弹出最小元素

    对于每个循环,请执行

    1. 找到所有 k 数组的最小元素,存储在B树中 C
    2. 找到 C 中的最小元素,然后从 C 中弹出此元素,然后从阵列中弹出。
    3. 重复直到 a-1 号码被弹出,然后转到4
    4. 将值从 a 存储到 b ,同时重复1到2
    5. 因此计算复杂度为 O(k * log(k)) + O(b * log(k)空间复杂度为 O(max(k,ba))。这似乎是最小的空间复杂性。

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

1 个答案:

答案 0 :(得分:4)

一种简单的方法是创建大小 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 < / em>您弹出的项目将是所有 k 数组中的 th 到b th 项目。

// 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)额外的内存。

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

另一种可能性。在每个 k 数组上运行 build-heap 方法。那是O(km)。然后执行合并以选择第一个 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)额外的内存。这是否比原始建议更快是值得怀疑的。这取决于 b m 之间的关系。 b 的值越大,速度越快。编写代码要复杂得多。