在O(n)时间内重叠约会?

时间:2012-09-05 14:18:04

标签: algorithm data-structures computational-geometry

我最近在接受采访时被问到这个问题。即使我能够提出 O n ²)解决方案,面试官仍然沉迷于 O n < / em>)解决方案。我还检查了一些我理解的 O n log n )的其他解决方案,但 O n )解决方案仍然不是我的一杯茶,它假定约会是按开始时间排序的。

任何人都能解释一下吗?

问题陈述:您将获得 n 约会。每个约会包含开始时间和结束时间。您必须有效地重新调整所有冲突的约会。

  

人:1,2,3,4,5   App Start:2,4,29,10,22
  App End:5,7,34,11,36

     

答案:2x1 5x3

O n log n )算法:单独的起点和终点如下:

  

2s,4s,29s,10s,22s,5e,7e,34e,11e,36e

然后对所有这些点进行排序(为简单起见,我们假设每个点都是唯一的):

  

2s,4s,5e,7e,10s,11e,22s,29s,34e,36e

如果我们连续开始没有结束,那么它是重叠的: 2s,4s是相邻的,所以重叠是

我们将保留“s”的计数,每次遇到它都会+1,当遇到e时我们将计数减少1。

5 个答案:

答案 0 :(得分:16)

O n )中不可能的一般解决方案。

您至少需要按约会开始时间排序,这需要 O n log n )。

如果列表已经排序,则 O n )解决方案。该算法基本上涉及检查下一个约会是否与任何先前的约会重叠。这个有一点微妙之处,因为你在执行它时实际上需要两个指向列表的指针:

  • 正在检查的当前约会
  • 到目前为止遇到的最新结束时间的约会(可能不是之前的约会)

O n )未分类案例的解决方案仅在您有其他约束时才存在,例如固定数量的预约时段。如果是这种情况,那么您可以使用HashSets来确定哪个约会覆盖每个时间段,算法大致如下:

  • 为每个时间段创建一个HashSet - O (1)因为时间段号是固定常量
  • 对于每个约会,将其ID号存储在它所涵盖的插槽的HashSets中 - O n ),因为更新恒定数量的时隙是 O (1)每次约会
  • 如果要迭代,请运行插槽,检查重叠 - O (1)(或 O n )重叠约会将其作为结果返回)

答案 1 :(得分:3)

假设您对开始和结束时间以及进行调度的分辨率有一些约束,似乎将每个约会转换为它执行/不使用的位图是相当容易的,然后在使用中的插槽上进行计数排序(也就是桶排序)。由于这两者都是线性的,结果应该是线性的(尽管如果我正确思考,它应该是时间数而不是约会数的线性)。

至少如果我将此问作为面试问题,我希望的主要内容是候选人询问这些限制(即,是否允许这些限制)。考虑到从现在开始约1000年来安排约会是不现实的,或者安排到​​甚至一分钟的精确度(更不用说像纳秒),它们会让我觉得是合理的约束,但你应该在假设之前先问一下。

答案 2 :(得分:1)

一种天真的方法可能是构建两个并行树,一个按起始点排序,另一个按每个间隔的结束点排序。这允许在O(log n)时间内丢弃每棵树的一半,但结果必须合并,需要O(n)时间。这给了我们O(n + log n)= O(n)的查询。

答案 3 :(得分:0)

这是我能想到的最好的伪代码。我试图尽可能地减少这个问题。这只比On ^ 2少(我认为)。

请注意,最后的输出不会显示给定约会在该约会的特定输出行上发生冲突的每个约会......但在某些时候会显示每个冲突。

另请注意,我按照开始时间的顺序以数字方式重命名约会。

output would be something like the following:

Appointment 1 conflicts with 2
Appointment 2 conflicts with
Appointment 3 conflicts with
Appointment 4 conflicts with 5
Appointment 5 conflicts with

appt{1},appt{2},appt{3} ,appt{4} ,appt{5}
  2      4       10       22      29
  5      7       11       36      34

伪代码

list=(1,2,3,4,5)
for (i=1,i<=5,i++)
    list.shift()   **removes first element
    appt{i}.conflictswith()=list

for (i=1,i<=n,i++)
{   number=n
    done=false
    while(done=false)
        {if (number>i)
            {if (appt(i).endtime() < appt(number).startime())
                {appt{i}.conflictswith().pop()}
             else
                {done=true}
             number--
             }
        else
            {done=true}
        }
}
for (i=1,i<=n,i++)
    print "Appointment ",i," conflicts with:",appt{i}.conflictswith()  

答案 4 :(得分:0)

我遇到了一个名为Interval树的数据结构,借助它我们可以在小于O(n log(n))的时间内找到间隔,具体取决于提供的数据