青训营X豆包MarsCode 技术训练营:打点计数器的区间合并Python题解 | 豆包MarsCode AI 刷题

49 阅读3分钟

打点计数器的区间合并

问题描述

小明正在设计一台打点计数器,该计数器可以接受多个递增的数字范围,并对这些范围内的每个唯一数字打点。如果多个范围之间有重叠,计数器将合并这些范围并只对每个唯一数字打一次点。小明需要你帮助他计算,在给定的多组数字范围内,计数器会打多少个点。

例如,给定三个数字范围 [1, 4], [7, 10], 和 [3, 5],计数器首先将这些范围合并,变成 [1, 5] 和 [7, 10],然后计算这两个范围内共有多少个唯一数字,即从 1 到 5 有 5 个数字,从 7 到 10 有 4 个数字,共打 9 个点。


测试样例

样例1:

输入:inputArray = [[1, 4], [7, 10], [3, 5]]
输出:9

样例2:

输入:inputArray = [[1, 2], [6, 10], [11, 15]]
输出:12

样例3:

输入:inputArray = [[1, 3], [2, 6], [8, 10]]
输出:9

解题思路

  1. 排序区间:先按区间的起始值对数组排序,便于后续的合并操作。
  2. 合并区间:遍历排序后的区间,如果当前区间的起始位置小于或等于前一区间的终止位置,则将它们合并。
  3. 计算总长度:遍历合并后的区间列表,计算区间长度并累加得到总覆盖长度。

代码

def solution(inputArray):
    sorted_input = sorted(inputArray, key=lambda x: x[0])
    merge_input = []
    current_start, current_end = sorted_input[0]
    for start, end in sorted_input[1:]:
        if start <= current_end:
            current_end = max(end, current_end)
        else:
            merge_input.append([current_start, current_end])
            current_start, current_end = start, end
    merge_input.append([current_start, current_end])
    tol = 0
    for start, end in merge_input:
        tol += end - start + 1
    return tol

if __name__ == "__main__":
    #  You can add more test cases here
    testArray1 = [[1,4], [7, 10], [3, 5]]
    testArray2 = [[1,2], [6, 10], [11, 15]]

    print(solution(testArray1) == 7 )
    print(solution(testArray2) == 9 )

关键代码解释

  • sorted函数:按每个区间的起始值对 inputArray 进行排序,以便将重叠或连续的区间放在相邻位置。
  • 使用for循环遍历排序好的区间:
    1. 通过遍历已排序的区间,对重叠或相邻的区间进行合并。
    2. start <= current_end 时,说明两个区间有重叠,将当前区间的结束位置扩展到更大的终点 current_end
    3. 如果没有重叠,将当前区间 [current_start, current_end] 加入到合并后的区间数组 merge_input 中,并更新为新的区间起始。
  • 计算所有合并区间的总长度:将每个区间的长度 end - start + 1 累加到 tol 中。

时间空间复杂度分析

  1. 排序时间复杂度:排序的时间复杂度为 O(n log n),其中 n 是区间的数量。

  2. 合并时间复杂度:遍历区间的复杂度为 O(n)

  3. 计算总长度时间复杂度:遍历合并后的区间进行长度计算,时间复杂度为 O(m),其中 m 是合并后区间的数量。

    总体时间复杂度O(n log n),主要由排序过程决定。

  • 空间复杂度O(n),其中 n 是合并后存储区间的额外数组 merge_input

优化方案

  1. 使用原地合并:如果可以在原数组上合并区间,减少对 merge_input 的额外空间需求,从而将空间复杂度降为 O(1)
  2. 减少tol的计算次数:计算 tol 时,可以直接在合并的过程中累加区间长度,避免再一次遍历。

优化代码

def solution(inputArray): 
    sorted_input = sorted(inputArray, key=lambda x: x[0]) 
    tol = 0 
    current_start, current_end = sorted_input[0] 
    for start, end in sorted_input[1:]: 
        if start <= current_end: 
            current_end = max(end, current_end) 
        else: 
            tol += current_end - current_start + 1 
            current_start, current_end = start, end 
    tol += current_end - current_start + 1 # 加上最后一个区间的长度 
    return tol