如何找到最大的常见范围?

时间:2015-08-21 00:59:11

标签: python algorithm datetime intervals

我有一个包含数百个这样的元组的列表:

list1 = [(epoch1, epoch2), (epoch3, epoch4), (epoch5, epoch6)]

每个元组以一个纪元的形式包含会话的开始和结束。

我想要找到的是同时发生的最大会话数。因此,如果epoch1 = 16:00, epoch2=16:30, epoch3=16:15, epoch4=16:45, epoch5=18:00, epoch6=19:00,答案为2,因为从16:15 to 16:30开始有两个会话处于活动状态(第一个和第二个会话)。

我认为这样做的一种方法是创建一个包含所有日期的新列表:

list2 = [epoch1, epoch2, epoch3, epoch4, epoch5, epoch6]  

然后遍历list2中的每对元素,并检查有多少list1个元组在其会话边框中包含它们。但我想这个解决方案很慢。有没有人有其他想法?

3 个答案:

答案 0 :(得分:3)

两种O(n log n)方式

设定:

sessions = [('16:00', '16:30'), ('16:15', '16:45'), ('18:00', '19:00')]

第一种方式:将开始和结束转换为事件(纪元+更改对),按升序顺序完成,并适当更新activemaxactive

events = (event
          for start, end in sessions
          for event in ((start, 1), (end, -1)))
active = maxactive = 0
for _, change in sorted(events):
    active += change
    maxactive = max(maxactive, active)
print(maxactive)

第二种方式:排序开始和结束独立,然后“并行”进行排序,更新所需的插槽数量以及当前有多少空闲。

starts, ends = map(sorted, zip(*sessions))
slots = free = e = 0
for start in starts:
    while ends[e] <= start:
        free += 1
        e += 1
    if free:
        free -= 1
    else:
        slots += 1
print(slots)

答案 1 :(得分:1)

这是一个经典问题。假设酒店需要为会议开始和结束时间安排会议室。需要几个房间?让我试着记住解决方案。

首先,按照开始时间排序会议。现在假装有无限数量的房间可用。在第一个会议室安排第一次会议。对于第二次会议,如果在第一会议室中的会议在满足两次开始时结束,则在第一个会议室安排,否则,在第二个会议室安排会议。对于每次连续会议,请查看所有会议室。如果一个人空缺,请在那里安排会议。如果没有,请添加一个新房间。

要确定这是有效的,请注意我们需要的最小房间数是同时开会的最大数量,因为每个会议都在不同的房间内进行。该算法提供了一种在这么多房间内安排会议的方法,因为我们从不添加新房间,除非会议开始时所有现有房间都被占用。 len(ending)是同时举行会议的最高水位。

要在python中执行此操作,我们只需要一个结束时间列表。设置ending[0] = epoch2。对于每个会议,循环结束列表。如果您在新会议开始时间之前找到一个,请将其更改为新会议结束时间。如果没有,请将新元素附加到结尾。最后,len(ending)就是答案。

每次更改结束列表时对它进行排序可能是值得的,因为它足以清楚地检查最早的结束时间。

更多信息:问题可以建模为图形,其中间隔是顶点,当且仅当它们相交时,两个顶点相邻。现在我们可以使用表示房间的颜色为顶点着色,并且没有两个相邻的顶点可以具有相同的颜色。所需的最小颜色数量就是答案。这种类型的图形称为区间图,奇怪的是。区间图有很多应用。 https://en.wikipedia.org/wiki/Interval_graph一般来说,查找图的色数是NP难的,但是这个算法表明区间图的色数可以用多项式时间计算。

答案 2 :(得分:0)

好吧,让我们考虑一下你问的最简单的故障。
同时运行多少个会话?
您如何看待这个人类?

同时,时代也是如此:

  • 一个时代将需要时代的开始 在另一个时代的开始和它结束之前。
  • 或者一个时代的结束需要在开始之间进行 另一个时代,在它结束之前。

但是当你想到这些是同一件事时,因为一个是真的,另一个必须是真的。

这意味着你可以检查每个元组中的第一个元素是否在任何其他元组的两个元素之间:

 count = 0
 for tuple1 in list1:
     for tuple2 in list1:
          if tuple2[1] > tuple1[0] > tuple2[0]:
              count += 2 #this means two overlap