区间合并问题 | 豆包MarsCode AI刷题

127 阅读3分钟

区间合并问题是一类十分经典的贪心问题 , 在豆包MarsCode AI刷题过程中我也有了新的感悟和总结 , 所以总结了一个通用一点的模板 ,并附上两道例题

区间合并的模板总结

先给大家贴一个通用的模板

from typing import List, Tuple

def merge(segs: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
    segs.sort()
    res = []
    st, ed = -2e9, -2e9 
    
    for seg in segs:
        if ed < seg[0]:

            if st != -2e9:
                res.append((st, ed))
            st, ed = seg
        else:

            ed = max(ed, seg[1])


    if st != -2e9:
        res.append((st, ed))
    
    return res


区间合并问题是一个典型的贪心算法问题,常出现在面试和竞赛中。以下以你的代码为例,总结区间合并问题的解题思路模板,并进行详细解析。


解题思路模板

  1. 排序:保证处理顺序

    • 按区间的左端点(start)升序排序。
    • 如果左端点相同,可以按右端点(end)排序,但通常不需要。
  2. 初始化变量:记录当前合并区间

    • 使用变量 sted 分别记录当前区间的起点和终点,初始值可以设为无效值(如极小值)。
  3. 遍历区间:判断是否重叠

    • 如果当前区间的起点大于当前记录区间的终点(st, ed),说明没有重叠:

      • 将当前记录的区间加入结果集。
      • 更新 sted 为当前区间的起点和终点。
    • 如果当前区间的起点小于等于记录区间的终点,说明有重叠:

      • 更新 ed 为当前记录的区间终点和当前区间终点的较大值,完成合并。
  4. 处理最后一个区间

    • 遍历完成后,需要将最后一个区间加入结果集。
  5. 返回结果集

    • 结果集即为合并后的区间列表。

我们基于这个总结的模板 ,只需要按照题意稍加改造代入

例题

1.唐门绝技:暴雨梨花针最少发射次数 - MarsCode

题目解析 :

唐三需要利用垂直发射的 暴雨梨花针,覆盖所有靶子(二维平面上的线段)。 这看似是一个二维的题 , 由于暴雨梨花针向上发射并覆盖 y = 100 范围。但我们只需要稍加思考就知道(我记得之前给的数据是y最大是100) , 我们只需要考虑x轴怎么丢针才能覆盖最多的区间 , 好的 ,成功转化为区间问题 , 套模板 , 代码如下

def solution(k, p, target):
    segs = [(i[0], i[1]) for i in target]
    segs.sort()

    st, ed = -1, -1
    res = 0

    for seg in segs:
        if ed < seg[0]:
            res += 1
            st, ed = seg[0], seg[1]
        else:
            st = max(seg[0], st)
            ed = min(seg[1], ed)

    return res % p

2. 打点计数器的区间合并 - MarsCode

题目解析 :

这题思路就更明显了,一眼就知道可以套模板 ,计数器的目标是接收多个 数字范围(区间) ,将这些范围中的所有数字合并,并对 每个唯一数字 打点。
步骤

  • 区间合并问题:将多个可能重叠的区间合并,得到最终的不相交区间。 直接使用区间合并模板
  • 计数问题:计算合并后的所有区间内的数字总数。
def solution(input_array):
    segs = [(x[0], x[1]) for x in input_array]
    segs.sort()

    res = 0
    st, ed = -2e9, -2e9

    for seg in segs:
        if ed < seg[0] - 1: 
            if st != -2e9:
                res += ed - st + 1  
            st, ed = seg[0], seg[1]
        else:
            ed = max(ed, seg[1])  

    if st != -2e9:
        res += ed - st + 1  

    return res

if __name__ == "__main__":
    # Test cases
    test_array1 = [[1, 4], [7, 10], [3, 5]]
    test_array2 = [[1, 2], [6, 10], [11, 15]]

    print(solution(test_array1) == 9)  # Expect true
    print(solution(test_array2) == 9)  # Expect true