我最近接受了一家社交媒体公司的采访,在那里我被问到以下问题。
有 k 未排序的数字长度为 m 的数组。目标是以高效且内存保守的方式在 k 数组中找到第a 到 b 我提出了两种可能的解决方案: 第一:暴力: 使用quickselect找到 b-th 最小元素的第一步,平均时间是从 O(km)到 O(km * log(m))总计。第2步时间复杂度为 O(km)。最后一步是在 C 中找到 a 第二:递归弹出最小元素 对于每个循环,请执行 因此计算复杂度为 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 可能非常大 答案 0 :(得分:4) 一种简单的方法是创建大小 b 的最大堆。然后运行以下代码: 这里的想法是你用第一个 b 项填充最大堆。然后,对于每个其他项,如果它小于堆上的最大项,则使用新项删除堆上的最大项。 当您处理完所有 km 项目时,最小的 b 项目在堆上,并且因为它是最大堆,所以第一个 ba < / em>您弹出的项目将是所有 k 数组中的 th 到b th 项目。 最坏的情况是第一个循环的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(b *(log m + log b + log b))。 总共给出O(km + b *(log m + log b + log b)),并且你会使用O(b)额外的内存。这是否比原始建议更快是值得怀疑的。这取决于 b 和 m 之间的关系。 b 的值越大,速度越快。编写代码要复杂得多。个最小元素,给定 a &lt; b &lt; 米。在后续问题中,“未排序的数组”被更改为MySQL数据库中不同表的列,可以使用哪些可能的高效数据结构以及相应的检索算法。
和 b-th 最小元素之间的元素,取 O((ba)日志(KB))。所以总需要 O(km)到 O(km * log(m)) + O((ba)log(kb) ))及时, O(kb)在太空中。
1 个答案:
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])
// 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()