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

时间:2010-02-11 14:15:32

标签: 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
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

如果有人知道一个算法,或者能指出我正确的方向,我 不胜感激。

TIA,

Steve F

9 个答案:

答案 0 :(得分:52)

以下必须工作:

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

    • 如果时间值标记为开始
    • ,则增加numberOfCalls
    • 如果时间值标记为结束
    • ,则减少numberOfCalls
    • 跟踪进程中numberOfCalls的最大值(以及发生时的时间值)
  4. 复杂性:O(n log(n))用于排序,O(n)用于遍历所有记录

答案 1 :(得分:1)

天真的方法怎么样:

  • 至少考虑开始时间和结束时间的最大值(这是你的范围R)
  • 采用最短的通话时间 - d(排序,O(nlog n))
  • 创建一个ceil(R / d)整数的数组C,零初始化
  • 现在,对于每次调用,将1添加到定义调用持续时间O的单元格中(n * ceil(R / d))
  • 遍历数组C并保存max(O(n))

我猜你也可以把它塑造成一个图形并且摆弄一下,但是此刻打败了我。

答案 2 :(得分:1)

在我看来,贪婪的算法将做必要的。问题类似于找出给定列车时刻表所需的平台数量。因此,重叠的数量将是所需平台的数量 callStart时间排序。开始将每个调用放入一个数组(一个平台)。因此,对于调用i and (i + 1),如果callEnd[i] > callStart[i+1],则它们不能进入相同的数组(或平台),尽可能多地放入第一个数组中。然后用其余的重复该过程,直到所有呼叫都用完为止。最后,数组的数量是最大重叠数。而复杂性将是O(n)

答案 3 :(得分:1)

以下页面提供了使用多种语言解决此问题的示例:http://rosettacode.org/wiki/Max_Licenses_In_Use

答案 4 :(得分:0)

您缩短了CallStart上的列表。然后,对于每个元素(i),您会看到所有j < i if

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

休息应该很容易。

答案 5 :(得分:0)

令人惊讶的是,对于某些问题解决方案有时只会突然出现......而且我认为我可能是最简单的解决方案;)

您可以用范围(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)

请注意,我目前不知道哪些电话有效;)

但就复杂性而言,评估非常简单:它在呼叫总持续时间方面是线性的。

答案 6 :(得分:0)

我认为解决这个问题的一个重要因素是识别每个结束时间是&gt; =呼叫的开始时间以及开始时间是否有序。因此,不要考虑阅读整个列表和排序,我们只需要按照开始时间顺序读取并从结束时间的最小堆中合并。这也解决了Sanjeev关于如何在开始之前处理结束的评论,当它们具有完全相同的时间值时,通过从结束时间最小堆轮询并且当它的值是<=下一个开始时间时选择它。

max_calls = 0
// A min-heap will typically do the least amount of sorting needed here.
// It's size tells us the # of currently active calls.
// Note that multiple keys with the same value must be supported.
end_times = new MinHeap()
for call in calls:
  end_times.add(call.end)
  while (end_times.min_key() <= call.start) {
    end_times.remove_min()
  }
  // Check size after calls have ended so that a start at the same time
  // doesn't count as an additional call.  
  // Also handles zero duration calls as not counting.
  if (end_times.size() > max_calls) max_calls = end_times.size()
}

答案 7 :(得分:0)

这似乎是reduce操作。类比是每次呼叫开始时,当前活动呼叫数增加1.每次呼叫结束时,当前呼叫数下降到零。

一旦有了这个活动呼叫流,您只需要对它们应用最大操作。这是一个有效的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

答案 8 :(得分:0)

这是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))