一、题目解析
本题需要计算同时进行的任务数量(最高并发数)。在具体场景中,任务会有开始时间和持续时间,问题的核心是如何高效处理多个任务的时间区间并统计最高重叠的任务数。
通过一个例子来直观理解:
- 输入任务:
[[1, 2], [2, 3]]。 - 任务1从第1秒开始,持续2秒,时间范围是
[1, 2]。 - 任务2从第2秒开始,持续3秒,时间范围是
[2, 4]。 观察重叠情况:任务1和任务2在第2秒时同时进行,因此最高并发数为2。
二、解题思路
要解决这个问题,可以将任务的时间区间转化为事件点,并利用事件点来统计并发数。
-
任务转化为事件:
- 每个任务的开始时间是一个“开始事件”。
- 每个任务的结束时间(开始时间 + 持续时间)是一个“结束事件”。
- 通过遍历输入的任务列表,将每个任务转化为两个事件,并存储在列表中。
-
事件排序:
- 按时间顺序对事件排序。如果两个事件时间相同,优先处理“结束事件”,以避免开始和结束时间重叠导致统计错误。
-
遍历事件:
- 遍历排序后的事件列表,使用一个计数器统计当前的并发数。
- 对于每个“开始事件”,并发数 +1;对于每个“结束事件”,并发数 -1。
- 在遍历过程中,记录并比较当前并发数和最大并发数,最终返回最高值。
这种方法通过对事件的排序和遍历,将复杂的问题转化为对简单时间点变化的统计。
三、代码实现
以下是完整代码实现:
def solution(n, array):
# 生成事件列表,每个任务生成两个事件
events = []
for x, y in array:
events.append((x, 1)) # 任务开始事件
events.append((x + y, -1)) # 任务结束事件
# 按时间排序,若时间相同,结束事件优先
events.sort(key=lambda event: (event[0], event[1]))
# 遍历事件,统计并发数
max_concurrent = 0
current_concurrent = 0
for _, delta in events:
current_concurrent += delta
max_concurrent = max(max_concurrent, current_concurrent)
return max_concurrent
if __name__ == "__main__":
# 测试用例
print(solution(2, [[1, 2], [2, 3]]) == 2) # 输出 2
print(solution(4, [[1, 2], [2, 3], [3, 5], [4, 3]]) == 3) # 输出 3
四、测试分析
测试用例1:
输入:n = 2, array = [[1, 2], [2, 3]]
过程:
- 任务1生成事件
(1, 1)和(3, -1)。 - 任务2生成事件
(2, 1)和(5, -1)。 - 排序后事件列表为:
[(1, 1), (2, 1), (3, -1), (5, -1)]。 - 遍历事件,当前并发数分别为
1 -> 2 -> 1 -> 0,最大并发数为2。 输出:2
测试用例2:
输入:n = 4, array = [[1, 2], [2, 3], [3, 5], [4, 3]]
过程:
- 排序后事件列表为:
[(1, 1), (2, 1), (3, -1), (3, 1), (4, 1), (5, -1), (6, -1), (7, -1)]。 - 遍历事件,当前并发数分别为:
1 -> 2 -> 1 -> 2 -> 3 -> 2 -> 1 -> 0。 输出:3
五、算法复杂度
-
时间复杂度:
- 生成事件列表需遍历
n个任务,复杂度为O(n)。 - 事件排序的复杂度为
O(n log n)。 - 遍历事件列表统计并发数的复杂度为
O(n)。 - 总时间复杂度为:
O(n log n)。
- 生成事件列表需遍历
-
空间复杂度:
- 事件列表存储
2n个事件,空间复杂度为O(n)。
- 事件列表存储
六、关键点总结
-
事件驱动的思想:
将区间问题转化为事件点处理,是一种高效解决区间重叠问题的通用方法。 -
排序规则:
当事件时间相同时,优先处理“结束事件”,避免重复统计并发数。 -
应用场景:
- 任务调度系统中的资源分配问题。
- 视频播放中的重叠播放时间统计。
- 数据分析中时间窗口的统计问题。
通过这道题,我们理解了如何运用排序与计数器解决复杂的区间问题,强化了对时间事件处理的逻辑