题目理解
题目要求我们设计一个打点计数器,该计数器可以接受多个递增的数字范围,并对这些范围内的每个唯一数字打点。如果多个范围之间有重叠,计数器将合并这些范围并只对每个唯一数字打一次点。我们需要计算在给定的多组数字范围内,计数器会打多少个点。
解题思路
- 排序区间:首先,我们可以对所有区间按起始点进行排序。这样可以帮助我们更容易地合并重叠的区间。
- 合并区间:遍历排序后的区间,如果当前区间的起始点小于或等于前一个区间的结束点,则说明这两个区间有重叠,可以合并。否则,将前一个区间加入结果列表,并开始一个新的区间。
- 计算总长度:合并完所有区间后,计算每个区间的长度并累加。
数据结构选择
- 列表:我们使用Python的列表来存储区间。列表的排序和遍历操作非常方便。
- 元组:每个区间用一个元组表示,例如
(start, end)。
算法步骤
-
排序:对输入的区间列表按起始点进行排序。
-
初始化:创建一个空的结果列表
merged_intervals和一个当前区间current_interval,初始值为排序后的第一个区间。 -
遍历区间:从第二个区间开始遍历,检查当前区间是否与前一个区间重叠。
- 如果重叠,合并这两个区间。
- 如果不重叠,将前一个区间加入结果列表,并更新当前区间为当前遍历的区间。
-
添加最后一个区间:遍历结束后,将最后一个区间加入结果列表。
-
计算总长度:遍历合并后的区间列表,计算每个区间的长度并累加。
代码实现
def solution(inputArray):
# 1. 对区间按起始点进行排序
inputArray.sort(key=lambda x: x[0])
# 2. 初始化结果列表和当前区间
merged_intervals = []
current_interval = inputArray[0]
# 3. 遍历所有区间
for interval in inputArray[1:]:
# 如果当前区间与前一个区间重叠,合并它
们
if interval[0] <=
current_interval[1]:
current_interval[1] = max
(current_interval[1],
interval[1])
else:
# 否则,将前一个区间加入结果列表,
并更新当前区间
merged_intervals.append
(current_interval)
current_interval = interval
# 4. 将最后一个区间加入结果列表
merged_intervals.append
(current_interval)
# 5. 计算合并后区间的总长度
total_length = 0
for interval in merged_intervals:
total_length += interval[1] -
interval[0] + 1
return total_length
if __name__ == "__main__":
testArray1 = [[1,4], [7, 10], [3, 5]]
testArray2 = [[1,2], [6, 10], [11,
15]]
print(solution(testArray1) == 9 )
print(solution(testArray2) == 12 )
代码解释
-
排序:
inputArray.sort(key=lambda x: x[0])这行代码按区间的起始点对所有区间进行排序。 -
初始化:
merged_intervals用于存储合并后的区间,current_interval用于存储当前正在处理的区间。 -
遍历区间:
if interval[0] <= current_interval[1]:检查当前区间是否与前一个区间重叠。current_interval[1] = max(current_interval[1], interval[1]):如果重叠,合并这两个区间。merged_intervals.append(current_interval):如果不重叠,将前一个区间加入结果列表。
-
添加最后一个区间:遍历结束后,将最后一个区间加入结果列表。
-
计算总长度:遍历合并后的区间列表,计算每个区间的长度并累加。
测试样例
-
样例1:
inputArray = [[1, 4], [7, 10], [3, 5]]- 排序后:
[[1, 4], [3, 5], [7, 10]] - 合并后:
[[1, 5], [7, 10]] - 总长度:
(5 - 1 + 1) + (10 - 7 + 1) = 5 + 4 = 9
- 排序后:
-
样例2:
inputArray = [[1, 2], [6, 10], [11, 15]]- 排序后:
[[1, 2], [6, 10], [11, 15]] - 合并后:
[[1, 2], [6, 10], [11, 15]] - 总长度:
(2 - 1 + 1) + (10 - 6 + 1) + (15 - 11 + 1) = 2 + 5 + 5 = 12
- 排序后:
-
样例3:
inputArray = [[1, 3], [2, 6], [8, 10]]- 排序后:
[[1, 3], [2, 6], [8, 10]] - 合并后:
[[1, 6], [8, 10]] - 总长度:
(6 - 1 + 1) + (10 - 8 + 1) = 6 + 3 = 9
- 排序后:
复杂度分析
- 时间复杂度:排序的时间复杂度为
O(n log n),遍历区间的时间复杂度为O(n),因此总时间复杂度为O(n log n)。 - 空间复杂度:主要的空间消耗在于存储合并后的区间,空间复杂度为
O(n)。
总结
通过排序和遍历,我们可以有效地合并重叠的区间,并计算合并后区间的总长度。这个算法的时间复杂度为 O(n log n),空间复杂度为 O(n),适用于大多数实际场景。
进一步优化
- 优化排序:如果输入的区间已经有序,可以跳过排序步骤,直接进行合并,从而将时间复杂度降低到
O(n)。 - 优化空间:如果不需要存储合并后的区间,可以直接在遍历过程中计算总长度,从而将空间复杂度降低到
O(1)。
通过这份详细的做题笔记,我们可以更好地理解题目的要求,掌握解题思路,并实现高效的代码。希望这份笔记对你有所帮助!