打点计数器的区间合并
问题描述
小明正在设计一台打点计数器,该计数器可以接受多个递增的数字范围,并对这些范围内的每个唯一数字打点。如果多个范围之间有重叠,计数器将合并这些范围并只对每个唯一数字打一次点。小明需要你帮助他计算,在给定的多组数字范围内,计数器会打多少个点。
例如,给定三个数字范围 [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
解题思路
- 排序区间:先按区间的起始值对数组排序,便于后续的合并操作。
- 合并区间:遍历排序后的区间,如果当前区间的起始位置小于或等于前一区间的终止位置,则将它们合并。
- 计算总长度:遍历合并后的区间列表,计算区间长度并累加得到总覆盖长度。
代码
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循环遍历排序好的区间:
- 通过遍历已排序的区间,对重叠或相邻的区间进行合并。
- 当
start <= current_end时,说明两个区间有重叠,将当前区间的结束位置扩展到更大的终点current_end。 - 如果没有重叠,将当前区间
[current_start, current_end]加入到合并后的区间数组merge_input中,并更新为新的区间起始。
- 计算所有合并区间的总长度:将每个区间的长度
end - start + 1累加到tol中。
时间空间复杂度分析
-
排序时间复杂度:排序的时间复杂度为
O(n log n),其中n是区间的数量。 -
合并时间复杂度:遍历区间的复杂度为
O(n)。 -
计算总长度时间复杂度:遍历合并后的区间进行长度计算,时间复杂度为
O(m),其中m是合并后区间的数量。总体时间复杂度:
O(n log n),主要由排序过程决定。
- 空间复杂度:
O(n),其中n是合并后存储区间的额外数组merge_input。
优化方案
- 使用原地合并:如果可以在原数组上合并区间,减少对
merge_input的额外空间需求,从而将空间复杂度降为O(1)。 - 减少
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