问题描述
小明正在设计一台打点计数器,该计数器可以接受多个递增的数字范围,并对这些范围内的每个唯一数字打点。如果多个范围之间有重叠,计数器将合并这些范围并只对每个唯一数字打一次点。小明需要你帮助他计算,在给定的多组数字范围内,计数器会打多少个点。
例如,给定三个数字范围 [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]] 输出:7
样例2:
输入:inputArray = [[1, 2], [6, 10], [11, 15]] 输出:9
样例3:
输入:inputArray = [[1, 3], [2, 6], [8, 10]]
问题分析
问题理解
我们需要计算多个递增数字范围内的唯一数字总数。如果多个范围之间有重叠,我们需要合并这些范围并只对每个唯一数字打一次点。
解题思路
-
排序:
- 首先,我们需要对输入的范围进行排序。排序的依据是范围的起始点
x[0]
,如果起始点相同,则按结束点x[1]
降序排序。这样做的目的是确保在处理重叠范围时,能够正确合并范围。
- 首先,我们需要对输入的范围进行排序。排序的依据是范围的起始点
-
合并范围:
- 初始化一个变量
current_end
来跟踪当前合并范围的终点。 - 遍历排序后的范围,如果当前范围的起始点
l
大于current_end
,说明当前范围与之前的范围不重叠,直接计算当前范围的长度并更新current_end
。 - 如果当前范围的终点
r
大于current_end
,说明当前范围与之前的范围部分重叠,只计算重叠部分的长度并更新current_end
。
- 初始化一个变量
-
计算总数:
- 在合并范围的过程中,累加每个合并范围的长度,最终得到唯一数字的总数
完整源代码
def solution(inputArray):
# 使用 sorted 函数和 lambda 表达式进行排序
sorted_array = sorted(inputArray, key=lambda x: (x[0], -x[1]))
# 初始化变量
sum = 0
current_end = -1
for l, r in sorted_array:
if l > current_end:
# 当前范围与之前的范围不重叠
sum += r - l + 1
current_end = r
elif r > current_end:
# 当前范围与之前的范围部分重叠
sum += r - current_end
current_end = r
return sum
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)
代码解释
起点升序排序
首先,按照区间的起点(左边界)进行升序排序。这确保了区间按照它们的开始位置从小到大排列。这种排序有助于我们依次处理每个区间,避免跳过或重复处理某些区间。
终点降序排序(当起点相同时)
当两个或多个区间的起点相同时,需要按照这些区间的终点(右边界)进行降序排序。这意味着,如果多个区间有相同的起点,那么终点更大的区间会排在前面。
为什么需要这样做?
- 避免错误的覆盖判断:如果不按照终点降序排序,可能会导致错误地判断两个区间是否覆盖。例如,如果有两个区间
[1, 5]
和[1, 3]
,如果按照起点升序后不进行终点降序排序,可能会错误地认为[1, 3]
覆盖了[1, 5]
,而实际上[1, 5]
是更大的区间,应该被优先考虑[1][4][5)。 - 确保最大覆盖:通过保证起点相同的区间中,终点更大的区间在前面,这样可以确保在合并或寻找覆盖区间时,总是选择覆盖范围最大的区间。
- 简化后续处理:这种排序方式简化了后续的逻辑判断,因为我们只需要比较当前区间的起点和前一个区间的终点即可,避免了复杂的交集判断。