Algorithm 在未排序的只读数组中查找中值

Algorithm 在未排序的只读数组中查找中值,algorithm,time-complexity,median,space-complexity,Algorithm,Time Complexity,Median,Space Complexity,给定一个包含n个元素的只读数组,用O(logn)空间和平均时间O(nlogn)查找数组中的中位数(大小为上限(n/2)-th个元素) 数组中的元素不同 数组未排序 不能更改数组中的任何值,只能读取它们 我曾考虑过使用快速排序的思想,但如果不更改数组,就不可能执行它。复制到另一个数组将超出所需的空间。您可以使用分治方法解决该问题,在最小值和最大值之间找到一个随机元素,检查它是否为中间值,中间值是否低于或高于它,并仅在数组的子范围上将问题缩小 将min设置为数组中的最小元素,将max设置为最大元

给定一个包含
n个
元素的只读数组,用
O(logn)
空间和平均时间
O(nlogn)
查找数组中的中位数(大小为
上限(n/2)
-th个元素)

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

我曾考虑过使用快速排序的思想,但如果不更改数组,就不可能执行它。复制到另一个数组将超出所需的空间。

您可以使用分治方法解决该问题,在最小值和最大值之间找到一个随机元素,检查它是否为中间值,中间值是否低于或高于它,并仅在数组的子范围上将问题缩小

  • min
    设置为数组中的最小元素,将
    max
    设置为最大元素

  • 在范围内选择一个随机数
    mid
    min
    ),如果没有这样的
    mid
    ,则
    min
    max
    为中间值,找到中间值,然后完成操作

  • 检查
    min
    mid
    max
    是否为中位数(线性搜索,计算大小)

    3.1。如果是这样,你就完了

    3.2。否则,中位数介于
    (最小值,中间值)
    (中间值,最大值)
    之间,并且您知道在哪里(如果更多值高于中间值或低于中间值)

    3.3。如果它在
    (最小,中间)
    ,则设置
    max=mid
    ,否则,设置
    min=mid

    3.4。返回到2


  • 正确性:

    • 如果算法找到一个数字,那么stop子句只是因为找到了中间值
    • 对于每次迭代,中值仍然在
      (min,max)
      (带归纳法的形式证明…),并且范围保证在每次迭代中缩小,因此算法保证停止并产生一些结果

    时间复杂性:

    • 步骤1:仅重复一次,并花费
      O(n)
      时间
    • 步骤2:花费
      O(n)
      时间(查找范围内的不同数字)并重复每次迭代
    • 步骤3:花费
      O(n)
      时间(通过每个范围是线性的)
    平均情况下有
    O(logn)
    迭代(类似于二进制搜索推理)

    这给了我们时间复杂度
    O(nlogn)


    空间复杂性:


    依赖于实现,但使用尾部递归(类似于上面的高级伪代码)实际上可以是
    O(1)
    。对于正则递归,这是堆栈的
    O(logn)

    这里是一个简单的算法。它包括通过跟踪中位数所在区间的上下限来搜索中位数

    设E为元素列表。将中值的上下限L和U设置为null

    对于e中的每个元素e

  • 如果L不为空且eU,e不能为中间值,则跳到下一个元素
  • 扫描E并计算E之前元素的数量B,以及E之后元素的数量A
  • 如果A=B,e为中间值,则终止。如果A=B+1,则没有单个中间值,但e在中间值点之前终止。如果B=A+1,则不存在单个中间值,但e在中间值点之后立即终止
  • 如果A>B,中位数在e之后,设置L=e。如果B>A,则中值在e之前,设置U=e
  • 空间复杂度为O(1)。平均时间复杂度最多为O(n2)和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.
    

    我不知道你的意思,但我必须将所有元素插入到两个堆中,这将需要O(n)spaceVoting才能重新打开正如目前所写的,很难准确说出你在问什么,问题陈述非常清楚。OP展示了他的两种方法,并解释了它们失败的原因(展示了自我研究)。如果其中一位投票人能解释他们的重新投票,我会很高兴的。@amit我正要问同样的问题,我想要一个算法,在给定的数组中找到中间值而不改变,我想知道他们为什么要结束这个问题!!谢谢你的回答。您能再解释一下为什么堆栈的内存中需要另一个O(logn)@Robert此解决方案需要
    O(1)
    额外的内存,但如果您将其移动到递归调用,而不将其优化为尾部递归,则会有
    O(logn)
    递归调用,每个调用都会将一些变量推送到调用堆栈,从而为您提供
    O(logn)
    space。这似乎是amit提出的算法的一个更难阅读的版本,20多分钟后发布。@tucuxi好吧,也许吧,但它更详细。amit只给出了高层次的步骤。我建议的算法可能更容易实现。