Algorithm 查找时间范围列表中的重叠(数量)

Algorithm 查找时间范围列表中的重叠(数量),algorithm,Algorithm,给定一个时间范围列表,我需要找到重叠的最大数量 以下是显示10分钟通话间隔的数据集,从 我正试图找出其中活动线的最大数量 间隔例如,从下面的示例中,同时处于活动状态的最大呼叫数是多少: CallStart CallEnd 2:22:22 PM 2:22:33 PM 2:22:35 PM 2:22:42 PM 2:22:36 PM 2:22:43 PM 2:22:46 PM 2:22:54 PM 2:22:49 PM 2:27:21 PM 2:22:57 PM 2:23:03 PM

给定一个时间范围列表,我需要找到重叠的最大数量

以下是显示10分钟通话间隔的数据集,从 我正试图找出其中活动线的最大数量 间隔例如,从下面的示例中,同时处于活动状态的最大呼叫数是多少:

CallStart   CallEnd
2:22:22 PM  2:22:33 PM
2:22:35 PM  2:22:42 PM
2:22:36 PM  2:22:43 PM
2:22:46 PM  2:22:54 PM
2:22:49 PM  2:27:21 PM
2:22:57 PM  2:23:03 PM
2:23:29 PM  2:23:40 PM
2:24:08 PM  2:24:14 PM
2:27:37 PM  2:39:14 PM
2:27:47 PM  2:27:55 PM
2:29:04 PM  2:29:26 PM
2:29:31 PM  2:29:43 PM
2:29:45 PM  2:30:10 PM
如果有人知道一个故事或者能给我指出正确的方向,我 我将不胜感激

蒂亚


Steve F

一个天真的方法怎么样:

  • 取最小的开始时间和最大的结束时间(这是您的范围R)
  • 取最短的呼叫持续时间--d(排序,O(nlog n))
  • 创建一个包含ceil(R/d)整数的数组C,初始化为零
  • 现在,对于每个调用,在定义调用持续时间O(n*ceil(R/d))的单元格中添加1
  • 循环数组C并保存最大值(O(n))
我想你也可以把它建模成一个图表,然后胡乱摆弄,但现在我还是被打败了。

以下几点一定行得通:

  • 对所有时间值进行排序,并为每个时间值保存开始或结束状态
  • numberOfCalls
    设置为0(计数变量)
  • 运行您的时间值并:

    • 如果时间值标记为开始,则增加numberOfCalls
    • 如果时间值标记为结束,则减少numberOfCalls
    • 跟踪过程中numberOfCalls的最大值(以及发生时的时间值)

  • 复杂性:O(n log(n))用于排序,O(n)用于遍历所有记录

    您可以在
    调用开始
    上缩短列表。然后对于每个元素(
    i
    ),您可以看到所有
    j
    如果

    CallEnd[j] > CallStart[i] // put it in a map with CallStart[i]  as the key and some count
    

    Rest应该足够简单。

    在我看来,贪婪算法将完成需要的工作。问题类似于找出给定列车时刻表所需的站台数量。因此,重叠的数量将是所需的平台数量。

    呼叫开始时间已排序。开始将每个调用放入一个数组(一个平台)。因此,对于call
    i和(i+1)
    ,如果
    callEnd[i]>callStart[i+1]
    ,则它们不能进入同一数组(或平台),在第一个数组中放入尽可能多的调用。然后对rest-one重复这个过程,直到所有调用都用尽。最后,数组的数量是重叠的最大数量。而复杂性将是
    O(n)

    令人惊讶的是,对于某些问题,解决方案有时只是从一个头脑中蹦出来。。。我想我可能是最简单的解决方案;)

    您可以以秒为单位表示时间,从范围的开始(0)到结束(600)。一个电话是一对时间

    Python算法:

    def maxSimultaneousCalls(calls):
      """Returns the maximum number of simultaneous calls
      calls   : list of calls
        (represented as pairs [begin,end] with begin and end in seconds)
      """
      # Shift the calls so that 0 correspond to the beginning of the first call
      min = min([call[0] for call in calls])
    
      tmpCalls = [(call[0] - min, call[1] - min) for call in calls]
      max = max([call[1] for call in tmpCalls])
    
      # Find how many calls were active at each second during the interval [0,max]
      seconds = [0 for i in range(0,max+1)]
      for call in tmpCalls:
        for i in range(call[0],call[1]):
          seconds[i] += 1
    
      return max(seconds)
    
    请注意,我不知道此时哪些呼叫处于活动状态;)


    但就复杂性而言,评估它是极其简单的:就呼叫的总持续时间而言,它是线性的。

    下页有许多语言解决此问题的示例:

    我认为解决此问题的一个重要因素是认识到每个结束时间都是>=呼叫的开始时间,并且开始时间是有序的。因此,我们不需要考虑整个列表的读取和排序,而只需要按照开始时间的顺序读取,并从结束时间的最小堆中合并。这也解决了Sanjeev关于当结束时间最小值堆具有完全相同的时间值时,应如何在开始之前处理结束的评论,方法是轮询结束时间最小值堆,并在其值为max_calls时选择它)max_calls=end_times.size() }
    这似乎是一个
    减少操作。类似地,每次启动呼叫时,当前活动呼叫数都会增加1。每次通话结束时,当前的通话次数将降至零

    一旦有了活动调用流,您所需要的就是对它们应用max操作。下面是一个工作python2示例:

    from itertools import chain
    inp = ((123, 125),
           (123, 130),
           (123, 134),
           (130, 131),
           (130, 131),
           (130, 132),)
    
    # technical: tag each point as start or end of a call
    data = chain(*(((a, 'start'), (b, 'end')) for a, b in inp))
    
    def r(state, d):
        last = state[-1]
        # if a call is started we add one to the number of calls,
        # if it ends we reduce one
        current = (1 if d[1] == 'start' else -1)
        state.append(last + current)
        return state
    
    max_intersect = max(reduce(r, sorted(data), [0]))
    
    print max_intersect
    

    下面是Python中的一个工作算法

    def maximumOverlap(calls):
        times = []
        for call in calls:
            startTime, endTime = call
            times.append((startTime, 'start'))
            times.append((endTime, 'end'))
        times = sorted(times)
    
        count = 0
        maxCount = 0
        for time in times:
            if time[1] == 'start':
                count += 1    # increment on arrival/start
            else:
                count -= 1    # decrement on departure/end
            maxCount = max(count, maxCount)  # maintain maximum
        return maxCount
    
    calls = [
    ('2:22:22 PM', '2:22:33 PM'),
    ('2:22:35 PM', '2:22:42 PM'),
    ('2:22:36 PM', '2:22:43 PM'),
    ('2:22:46 PM', '2:22:54 PM'),
    ('2:22:49 PM', '2:27:21 PM'),
    ('2:22:57 PM', '2:23:03 PM'),
    ('2:23:29 PM', '2:23:40 PM'),
    ('2:24:08 PM', '2:24:14 PM'),
    ('2:27:37 PM', '2:39:14 PM'),
    ('2:27:47 PM', '2:27:55 PM'),
    ('2:29:04 PM', '2:29:26 PM'),
    ('2:29:31 PM', '2:29:43 PM'),
    ('2:29:45 PM', '2:30:10 PM'),
    ]
    print(maximumOverlap(calls))
    

    的确很简单,我发布了另一个不需要排序的解决方案,我想知道它在性能方面的表现如何……如何跟踪numberOfCalls的最大值?@ygnhzeus,将其保存在一个单独的变量中,并在当前numberOfCalls值大于以前的maximumIt遗漏一个用例时更新它。假设在精确的一个点上有多个起点和终点,即假设在2:25:00有2个起点和3个终点。因此,排序后的范围间隔将在2:25:00有5个值,以随机顺序开始2次,结束3次。但要使algo正常工作,结束应该先于开始。@vladimir非常好而且清晰的解决方案,Thnks。但是,如果我们想返回所有的重叠时间,而不是重叠的数量,该怎么办?再次感谢
    def maximumOverlap(calls):
        times = []
        for call in calls:
            startTime, endTime = call
            times.append((startTime, 'start'))
            times.append((endTime, 'end'))
        times = sorted(times)
    
        count = 0
        maxCount = 0
        for time in times:
            if time[1] == 'start':
                count += 1    # increment on arrival/start
            else:
                count -= 1    # decrement on departure/end
            maxCount = max(count, maxCount)  # maintain maximum
        return maxCount
    
    calls = [
    ('2:22:22 PM', '2:22:33 PM'),
    ('2:22:35 PM', '2:22:42 PM'),
    ('2:22:36 PM', '2:22:43 PM'),
    ('2:22:46 PM', '2:22:54 PM'),
    ('2:22:49 PM', '2:27:21 PM'),
    ('2:22:57 PM', '2:23:03 PM'),
    ('2:23:29 PM', '2:23:40 PM'),
    ('2:24:08 PM', '2:24:14 PM'),
    ('2:27:37 PM', '2:39:14 PM'),
    ('2:27:47 PM', '2:27:55 PM'),
    ('2:29:04 PM', '2:29:26 PM'),
    ('2:29:31 PM', '2:29:43 PM'),
    ('2:29:45 PM', '2:30:10 PM'),
    ]
    print(maximumOverlap(calls))