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

Python 在k个数组中查找第a到第b个最小元素的有效方法,python,mysql,algorithm,sorting,time-complexity,Python,Mysql,Algorithm,Sorting,Time Complexity,我最近接受了一家社交媒体公司的采访,他们问了我以下问题。 有k个长度为m的未排序数组。目标是在给定a

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

有k个长度为m的未排序数组。目标是在给定a 我提出了两种可能的解决方案:

第一:暴力:

  • 首先使用quickselect查找每个数组的第b个最小元素
  • 然后找到小于每个数组第b个元素的元素,并将它们存储到大小为k*b的b树C中
  • 然后找到C中的第a到第b个最小元素
  • 对于使用quickselect查找第b个最小元素的第一步,平均时间总计为O(km)到O(km*log(m))。步骤2时间复杂度为O(km)。最后一步是以O((b-a)log(kb))为单位,查找C中第a个和第b个最小元素之间的元素。所以total在时间上需要O(km)到O(km*log(m))+O((b-a)log(kb)),在空间上需要O(kb)

    秒:递归地弹出最小的元素

    对于每个循环,执行以下操作

  • 找到所有k数组的最小元素,存储在B树C中
  • 找到C中最小的元素,从C中弹出这个元素,然后从数组中取出它
  • 重复此操作,直到弹出a-1编号,然后转到4
  • 存储从a到b的值,同时重复1到2
  • 因此计算复杂度为O(k*log(k))+O(b*log(k)),空间复杂度为O(max(k,b-a))。这似乎是最小的空间复杂度


    更有效的方法是什么?特别是quickselect最糟糕的情况是O(n^2),它看起来太大了,对于空间中位数O(kb)处的b=m/2或时间中位数O(b*log(k))被认为太大了。对于MySQL数据库,我建议在解决方案1中使用B-tree,它在空间和时间上都有O(kb)的情况下提供快速的排名选择,并且数据库中有k个查询。在解决方案2中,据说MySQL数据库中的b查询太大,b树插入为O(log(m)),其中m可能非常大。

    一个简单的方法是创建一个大小为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])
    
    最坏的情况是,使用O(b)额外内存,第一个循环为O(km log b),第二个循环为O(b log b)

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

    还有一种可能性。在每个k数组上运行buildheap方法。那是O(公里)。然后进行合并以选择前b项。合并需要:

    • O(log m)从源阵列中删除每个项
    • O(日志b)将每个项添加到合并堆
    • O(日志b)从合并堆中删除每个项
    第二步是O(b*(logm+logb+logb))


    这样就得到了O(km+b*(logm+logb+logb)),并且需要使用O(b)额外的内存。这是否会比最初的建议更快是值得怀疑的。这取决于b和m之间的关系。b的值越大,速度越快。而且代码编写起来要复杂得多。

    你得到这份工作了吗?
    // 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()