这个算法不会在O(m log n)中运行吗?

时间:2015-03-10 20:11:48

标签: java algorithm runtime big-o time-complexity

我正在处理一个面试问题 Glassdoor Software Engineer

问题是

给定一百万个数字的列表,你将如何以有效的方式从列表中找到前n个数字

以下是作者从同一链接中提供的解决方案

      
  1. 创建一个最小堆
  2.   
  3. 取m个元素的前n个并放入堆(O(n))
  4.   
  5. 对于每个(m-n)个剩余元素,如果它大于堆的find-min,则插入堆并删除min。 (最坏情况 O((m-n)log n )如果列表已排序。
  6. 净结果是您可以在 O(n)内存使用情况和最坏情况 O((m-n)logn)运行时执行此操作。

    我同意作者的算法和作者对该算法空间复杂度的评估。我遇到的问题是作者对插入堆中的运行时和整体时间的分析

    对于“取m个元素中的前n个并放入堆中”的步骤,不会运行 O(nlogn)?至少根据我的课堂笔记 Heap Add,插入将是 O(logn),因为你要插入n个元素,整个步骤的运行时间将是 O(nlogn)

    考虑到这一点,整个算法的整体运行时间不会是Big Oh Addition

     
     O(nlogn + (m-n)logn) = O(mlogn) 

2 个答案:

答案 0 :(得分:3)

使用这种方法构建堆,是的,但是有一个O(n)算法可以将数组转换为堆。有关详细信息,请参阅http://en.wikipedia.org/wiki/Binary_heap#Building_a_heap

即,对于该问题存在O(m)时间,O(n)存储器解决方案,例如通过例如实现。番石榴的Ordering.leastOf。一个实现是

  • 创建一个缓冲区,大小为2n的数组
  • 循环遍历原始数组,将元素添加到缓冲区
  • 每当缓冲区已满时,使用O(n)quickselect只保留缓冲区中最高的n个元素并丢弃其余元素。
  • 使用最后一个quickselect从缓冲区中提取最高n个元素

这需要O(m / n)个快速选择,每个选择O(n),总时间为O(m)。

答案 1 :(得分:2)

  

对于步骤"取m个元素中的前n个并放入堆中,不会在O(nlogn)中运行?

不一定。您可以从n中的O(n)元素创建堆。请参阅here了解如何实现这一目标。

所以你有O(n + (m - n)log n) = O((m - n)log n) = O(m log n)。仅当n被视为常量时,最后一步才是正确的,否则您应该像作者一样将其保持为m - n

后续问题:你能解决O(m)中的整个问题吗?