专栏首页用户2133719的专栏常见编程模式之合并区间

常见编程模式之合并区间

4. 合并区间(Merge Intervals)

基本原理及应用场景

合并区间模式是一种处理重叠区间的有效手段。在很多包含区间的问题中,我们可能需要去找出重叠的部分或将重叠部分合并。给定两个区间,其关联方式有如下六种:

在以下场景中,我们可能会用到合并区间:

  • 题目涉及生成只包含互斥区间的列表
  • 题目涉及重叠区间

经典例题

56. 合并区间(Medium)

给出一个区间的集合,请合并所有重叠的区间。

「示例」

输入: intervals = [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

先基于左边界对区间集合进行排序,这样将区间的关联关系限定在前三种,我们只需要对下面两种重叠情况进行合并即可:

基于上述思想,代码实现如下:

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if len(intervals) < 2: return intervals
        intervals.sort(key = lambda x: x[0]) # 对集合排序(按左边界)
        
        merged = []
        start = intervals[0][0]
        end = intervals[0][1]

        for i in range(1, len(intervals)):
            interval = intervals[i] # 从第二个区间开始,逐个比较
            if interval[0] <= end: # 当前区间的左边界小于上一个区间的右边界,说明有重叠
                end = max(interval[1], end) # 合并后的右边界为两个区间右边界的最大值,左边界为上一个区间的(因为已排序)
                # 合并后继续遍历,直到不重叠再添加到结果中
            else:
                merged.append([start, end]) # 不存在重叠,将上一个区间添加到结果中
                start = interval[0]
                end = interval[1]
        
        merged.append([start, end]) # 将最后一组区间添加到结果中
        return merged

986. 区间列表的交集(Medium)

给定两个由一些「闭区间」组成的列表,每个区间列表都是成对不相交的,并且已经排序。返回这两个区间列表的交集。 (形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b。两个闭区间的交集是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3]。)

「示例」

输入:A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

我们可以用两个指针分别指向 A 和 B,比较其当前指向的区间。由于 A 和 B 内部的区间均已排序且不相交,所以对于存在重叠的两个区间,较小的末端点只可能与一个区间相交,否则会在列表内部出现两个相交的区间,与题意不符。所以我们只需要按顺序比较区间,存在重叠则合并区间,并移动末端点较小的区间所在列表的指针即可。基于上述思想,可以写出如下代码:

class Solution:
    def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
        ans = []
        i, j = 0, 0

        while i < len(A) and j < len(B):
            lo = max(A[i][0], B[j][0])
            hi = min(A[i][1], B[j][1])
            if lo <= hi: # 存在重叠
                ans.append([lo, hi])
            
            # 移动较小末端点所在列表的指针,可能存在同时移动的情况
            if hi == A[i][1]:
                i += 1
            if hi == B[j][1]:
                j += 1
        
        return ans

57. 插入区间(Hard)

给出一个无重叠的,按照区间起始端点排序的区间列表。 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

「示例」

输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。

这道题的一种简单做法是参考 56 题,先把新的区间添加到列表中,然后执行 56 题的代码即可。不过由于本题中给定的是无重叠已排序区间列表,所以再次进行排序是没有必要的,可以仅遍历一次合并即可,具体算法如下:

  • newInterval 之前开始的区间添加到输出
  • 添加 newInterval 到输出,若 newInterval 与输出中的最后一个区间重合则合并他们
  • 一个个添加区间到输出,若有重叠部分则合并他们

对应的代码实现如下:

class Solution:
    def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
        new_start, new_end = newInterval
        idx, n = 0, len(intervals)
        output = []

        # 将所有新区间之前的区间添加到结果中
        while idx < n and new_start > intervals[idx][0]:
            output.append(intervals[idx])
            idx += 1
        
        # 如果输出为空或最后一个区间和新区间不重合
        if not output or output[-1][1] < new_start:
            output.append(newInterval)
        # 如果存在重合,则进行合并
        else: 
            output[-1][1] = max(output[-1][1], new_end)
        
        # 添加之后的区间,存在重合则合并
        while idx < n:
            interval = intervals[idx]
            start, end = interval
            idx += 1
            if output[-1][1] < start:
                output.append(interval)
            else:
                output[-1][1] = max(output[-1][1], end)
        return output

本文分享自微信公众号 - 口仆(roito33),作者:口仆

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 本体入门(二):OWL 本体构建指南f

    本文将介绍如何通过 Protege 构建 OWL 本体,文中使用的软件版本为 mac 上的 protege 5.5.0 桌面版。

    口仆
  • 医学统计学:计量资料的统计描述

    「统计描述」是指用统计指标和适当的统计图表来描述资料的「分布规律」及其「数量特征」,本文将介绍统计描述中的常见概念。

    口仆
  • 《SICP》读书笔记之一:构造过程抽象(上)

    本章节将介绍有关计算过程(computational process)的知识。计算过程是存在于计算机里的一类抽象事物。在其演化过程中,这些过程会去操作一些被称为...

    口仆
  • 秒懂力扣区间题目:重叠区间、合并区间、插入区间

    今天的力扣打卡题是 57. 插入区间 ,我们再顺便练习两道类似的简单区间题目,比如:判断区间是否重叠(252. 会议室)、56. 合并区间。这类面试题目还挺讨巧...

    灵魂画师牧码
  • 定义区间DP

    区间动态规划问题一般都是考虑,对于每段区间,他们的最优值都是由几段更小区间的最优值得到,是分治思想的一种应用,将一个区间问题不断划分为更小的区间直至一个元素组成...

    用户1624346
  • gin用Request.Form获取不到参数的问题

    问题: 用Postman请求,ctx.Request.Form能获取到GET参数,却不能获取到POST参数

    槽痞
  • phalcon-入门篇9(view层基础使用)

    #phalcon-入门篇9(view层基础使用)# ? 本教程基于phalcon2.0.9版本 ##前言## 先在这里感谢各位phalcon技术爱好者,我们提供...

    喵了个咪233
  • 张钦坤:云计算、开放平台与服务商版权责任

         云计算是借助虚拟技术对服务器资源的大幅提升,在此基础上可以为众多企业提供所需的服务,降低企业运营成本。互联网开放平台是依托于云计算技术而进行的商业模...

    腾讯研究院
  • Redis系列——10.字典结构

    大年初五送财神,emmm,希望今年暴富,每年都是这么单纯简单的小愿望,没有一次让我实现的。

    陈琛
  • 腾讯音乐联合腾讯文旅为河南开封传唱黄河之韵  重塑非遗音乐

    ? 为响应黄河流域生态保护和高质量发展国家战略,保护传承弘扬黄河文化,挖掘整合和宣传展示开封文旅资源,讲好黄河故事,8月8日晚,“宋词中国 世界开封”国风宋词...

    腾讯文旅

扫码关注云+社区

领取腾讯云代金券