小M多任务下载器问题 | 豆包MarsCode AI刷题

104 阅读3分钟

问题分析

我们需要解决的是 任务并发问题,即在同一时间段内,最多有多少个任务同时进行。可以将任务的时间范围视为一个区间问题,通过记录开始时间和结束时间来计算最高并发数。

思路

  1. 将任务转化为事件

    • 每个任务的开始时间可以看作是一个事件,表示“一个任务开始”。
    • 每个任务的结束时间可以看作是一个事件,表示“一个任务结束”。
  2. 记录事件

    • 将所有任务的开始时间和结束时间记录为事件。
    • 对于每个任务的结束时间,需要注意的是它在 开始时间 + 持续时间 的下一秒结束,因此结束时间为 x + y
  3. 事件排序

    • 按时间对事件排序。如果时间相同,则优先处理“任务结束”的事件(先结束再开始,这样能避免冲突)。
  4. 计算并发数

    • 遍历排序后的事件数组,维护一个计数器记录当前同时进行的任务数。
    • 遇到“任务开始”事件,计数器加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]))
    
    # 计算并发数
    concurrent = 0
    max_concurrent = 0
    
    for _, event_type in events:
        concurrent += event_type  # +1 表示任务开始,-1 表示任务结束
        max_concurrent = max(max_concurrent, concurrent)
    
    return max_concurrent


if __name__ == "__main__":
    # 测试用例
    print(solution(2, [[1, 2], [2, 3]]) == 2)  # 示例 1
    print(solution(4, [[1, 2], [2, 3], [3, 5], [4, 3]]) == 3)  # 示例 2
    print(solution(5, [[1, 3], [3, 4], [2, 2], [6, 5], [5, 3]]) == 3)  # 示例 3

代码详解

  1. 事件生成

    • 遍历任务列表 array,将每个任务的开始时间和结束时间分别加入 events 列表。
  2. 事件排序

    • 按时间排序 events,如果时间相同,优先处理任务结束事件。
    • 例如,任务 [[1, 2], [2, 3]] 产生的事件为:[(1, 1), (3, -1), (2, 1), (5, -1)],排序后为:[(1, 1), (2, 1), (3, -1), (5, -1)]
  3. 并发计算

    • 遍历排序后的 events,根据事件类型更新当前并发任务数。
    • 同时记录最大并发数 max_concurrent

复杂度分析

  1. 时间复杂度

    • 生成事件的复杂度为 O(n)O(n)
    • 排序事件的复杂度为 O(nlogn)O(n \log n)
    • 遍历事件的复杂度为 O(n)O(n)
    • 总体时间复杂度为 O(nlogn)O(n \log n)
  2. 空间复杂度

    • 额外存储事件数组,复杂度为 O(n)O(n)

测试结果

示例 1

solution(2, [[1, 2], [2, 3]])
# 输出: 2

示例 2

solution(4, [[1, 2], [2, 3], [3, 5], [4, 3]])
# 输出: 3

示例 3

solution(5, [[1, 3], [3, 4], [2, 2], [6, 5], [5, 3]])
# 输出: 3

总结

  • 本解法通过事件排序和计数实现了对最高并发数的高效计算。
  • 排序解决了任务重叠问题,遍历过程记录并发数变化,最终得出最高并发数。