打点计数器的区间合并 青训营打卡day8 | 包MarsCode AI刷题

3 阅读4分钟

问题描述

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

例如,给定三个数字范围 [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]]

问题分析

问题理解

我们需要计算多个递增数字范围内的唯一数字总数。如果多个范围之间有重叠,我们需要合并这些范围并只对每个唯一数字打一次点。

解题思路

  1. 排序

    • 首先,我们需要对输入的范围进行排序。排序的依据是范围的起始点 x[0],如果起始点相同,则按结束点 x[1] 降序排序。这样做的目的是确保在处理重叠范围时,能够正确合并范围。
  2. 合并范围

    • 初始化一个变量 current_end 来跟踪当前合并范围的终点。
    • 遍历排序后的范围,如果当前范围的起始点 l 大于 current_end,说明当前范围与之前的范围不重叠,直接计算当前范围的长度并更新 current_end
    • 如果当前范围的终点 r 大于 current_end,说明当前范围与之前的范围部分重叠,只计算重叠部分的长度并更新 current_end
  3. 计算总数

    • 在合并范围的过程中,累加每个合并范围的长度,最终得到唯一数字的总数

完整源代码

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)。
  • 确保最大覆盖:通过保证起点相同的区间中,终点更大的区间在前面,这样可以确保在合并或寻找覆盖区间时,总是选择覆盖范围最大的区间。
  • 简化后续处理:这种排序方式简化了后续的逻辑判断,因为我们只需要比较当前区间的起点和前一个区间的终点即可,避免了复杂的交集判断。