在未排序的只读数组中找到中位数

时间:2019-06-04 09:37:57

标签: algorithm time-complexity median space-complexity

给出一个包含n个元素的只读数组,找到数组中的中位数(第ceiling(n/2)个元素,大小为O(logn),平均时间为{{1 }}。

  • 数组中的元素不同。
  • 数组未排序。
  • 您不能更改数组中的任何值,只能读取它们

我考虑过使用Quicksort的想法,但是如果不更改数组就无法执行它。而复制到另一个数组将超出所需的空间。

2 个答案:

答案 0 :(得分:5)

您可以使用分而治之的方法来解决它,在最小值和最大值之间找到一个随机元素,检查它的中位数,是中位数低于还是高于中位数,然后仅在数组的子范围。

  1. min设置为数组中的最小元素,并将max设置为数组中的最大元素。

  2. 选择范围(mid)中的随机数min < mid < max,如果没有这样的mid,则minmax是中位数,找到完成的工作。

  3. 检查minmidmax中的任何一个是否为中位数(线性搜索,请计算有多少个是大/小)。

    3.1。如果是这样,您就完成了。

    3.2。否则,中位数在(min,mid)(mid,max)之间,并且您知道位置在哪里(如果高于中间值或低于中间值)。

    3.3。如果位于(min,mid)中,请设置max = mid,否则,请设置min = mid

    3.4。返回2。


正确性:

  • 如果算法找到一个数字,则stop子句仅是由于找到了中位数。
  • 对于每次迭代,中位数仍在(min,max)中(带有归纳法的形式证明..),并且保证了每次迭代的范围都会缩小,因此可以保证算法停止并产生一些结果。 / li>

时间复杂度:

  • 第1步:仅重复一次,并花费O(n)时间。
  • 第2步:花费O(n)时间(在范围内找到不同的数字)并重复每次迭代。
  • 第3步:花费O(n)时间(遍历每个范围都是线性的)。

平均情况下有O(logn)个迭代(类似于二进制搜索推理)。

这使我们O(nlogn)的时间复杂度


空间复杂度:

依赖于实现,但是具有尾递归(类似于上面的高级伪代码)实际上可以是O(1)。对于常规递归,对于堆栈,这是O(logn)

答案 1 :(得分:0)

这是一个简单的算法。它包括通过跟踪中间值所在的区间的上下边界来搜索中间值。

让E为元素列表。将中位数的上下限L和U设置为空。

对于E中的每个元素e,

  1. 如果L不为null并且e U,e不能为中位数,请跳到下一个元素。
  2. 扫描E并计算e之前的元素数量B,以及e之后的元素数量A。
  3. 如果A = B,e是中位数,则终止。如果A = B + 1,则没有单个中位数,但是e紧接中位数点之前,终止。如果B = A +1,则没有单一的中位数,但是e紧接中位数点之后,终止。
  4. 如果A> B,中位数在e之后,则设置L = e。如果B> A,则中位数在e之前,则设置U = e。

空间复杂度为O(1)。平均时间复杂度最高为O(n 2 )和O(nlogn)。

示例:

E = [2 4 7 9 0 6 5]
       L,U = null,null  Initial state.
e = 2  L,U = 2,null     Update L.
e = 4  L,U = 4,null     Update L.
e = 7  L,U = 4,7        Update U.
e = 9  L,U = 4,7        Skip 9.
e = 0  L,U = 4,7        Skip 0.
e = 6  L,U = 4,6        Update U.
e = 5  Median is 5      Terminate.