查找未排序数组的中位数

Luv*_*Luv 46 algorithm heap median

为了找到未排序数组的中位数,我们可以在O(nlogn)时间内为n个元素创建一个最小堆,然后我们可以逐个提取n/2个元素来获得中值.但这种方法需要O(nlogn)时间.

我们可以在O(n)时间内通过某种方法做同样的事情吗?如果可以的话,请告诉或建议一些方法.

das*_*ght 40

您可以使用Median of Medians算法在线性时间内查找未排序数组的中位数.

  • @KevinKostlan它实际上不是近似的,它是真正的中位数,它在线性时间内找到它.请注意,在找到中位数的中位数(保证大于元素的至少30%且小于元素的至少30%)之后,使用该数据透视对数组进行分区.然后你将(如果需要的话)递归到那些最多为原始数组大小的70%的数组中,以便找到真实的中位数(或者在一般情况下为k统计量). (8认同)

rka*_*ach 16

我已经提出了@dasblinkenlight答案,因为Medians of Medians算法实际上在O(n)时间内解决了这个问题.我只想补充说,这个问题可以通过使用堆来在O(n)时间内解决.通过使用自下而上的方法,可以在O(n)时间内构建堆.请查看以下文章,了解堆排序的详细说明

假设您的数组有N个元素,则必须构建两个堆:包含前N/2个元素的MaxHeap(如果N为奇数,则为(N/2)+1)和包含其余元素的MinHeap.如果N是奇数,则中位数是MaxHeap的最大元素(通过获得最大值,O(1)).如果N是偶数,那么你的中位数是(MaxHeap.max()+ MinHeap.min())/ 2这也需要O(1).因此,整个操作的实际成本是堆积构建操作,即O(n).

BTW这个MaxHeap/MinHeap算法也适用于您事先不知道数组元素的数量(如果您必须为例如整数流解决相同的问题).您可以在下面的文章中间整数流中查看有关如何解决此问题的更多详细信息

  • 为什么这样做?假设你的数组是[3,2,1].然后我们将前2个放在最大堆中:[3,2],因此3将是根,所以2,它的子必须小于它.并且,我们在最小堆中有[1].根据这个算法,我们然后选择maxHeap的max(root)作为我们的中位数.这不会给我们3吗? (3认同)

Bro*_*ass 10

Quickselect在O(n)中工作,这也用在Quicksort的分区步骤中.

  • 我认为quickselect不一定只能在一次运行中给出中位数.这取决于您的枢轴选择. (4认同)
  • 快速选择介于 O(n) 和 O(n^2) 之间。 (2认同)

小智 9

快速选择算法可以在线性(O(n))运行时间中找到数组的第k个最小元素.这是python中的一个实现:

import random

def partition(L, v):
    smaller = []
    bigger = []
    for val in L:
        if val < v: smaller += [val]
        if val > v: bigger += [val]
    return (smaller, [v], bigger)

def top_k(L, k):
    v = L[random.randrange(len(L))]
    (left, middle, right) = partition(L, v)
    # middle used below (in place of [v]) for clarity
    if len(left) == k:   return left
    if len(left)+1 == k: return left + middle
    if len(left) > k:    return top_k(left, k)
    return left + middle + top_k(right, k - len(left) - len(middle))

def median(L):
    n = len(L)
    l = top_k(L, n / 2 + 1)
    return max(l)
Run Code Online (Sandbox Code Playgroud)