【算法·命运-9】区间合并及其例题

区间合并简介

区间合并问题是指在给定多个区间的情况下,找出能够合并的区间,使得最终的结果区间尽量少,并且没有重叠。这个问题通常出现在处理一系列任务或事件的时间段、区间操作、或者连续的数字范围问题中。

例如,给定一些时间段,你需要合并所有相交或相邻的时间段,使得最终的结果更加简洁。


区间合并的基本思路

  1. 排序

    • 首先,按照区间的起始位置进行排序。排序的目的是为了确保所有的重叠区间可以在顺序上被依次处理。
  2. 合并

    • 初始化一个结果列表,遍历每个区间。
    • 对于当前区间,如果它与结果列表中的最后一个区间重叠(即起始点小于等于结果区间的结束点),则合并这两个区间;否则,将当前区间加入结果列表。
  3. 合并条件

    • 区间 [a, b][c, d] 可以合并当且仅当 b >= c,即第一个区间的结束位置不大于第二个区间的开始位置。

区间合并的解题步骤

  1. 排序:按照每个区间的起始点对区间进行排序。
  2. 合并:遍历排序后的区间,逐一检查是否能合并到结果区间中。
    • 如果可以合并,更新结果区间的结束位置。
    • 如果不能合并,将当前区间添加到结果区间中。

区间合并经典例题


例题1:合并区间

题目描述: 给定一个区间的集合 intervals,请合并所有重叠的区间。返回合并后的区间。

解法

  1. 对所有区间按起始点进行排序。
  2. 使用一个空的结果列表,遍历排序后的区间。
  3. 如果当前区间和结果中的最后一个区间重叠,合并它们;否则,直接将当前区间加入结果列表。

代码实现

def merge_intervals(intervals):
    # Step 1: 按照区间的起始位置进行排序
    intervals.sort(key=lambda x: x[0])
    
    merged = []
    for interval in intervals:
        # 如果 merged 为空或当前区间与 merged 中最后一个区间不重叠,则直接添加
        if not merged or merged[-1][1] < interval[0]:
            merged.append(interval)
        else:
            # 如果当前区间与 merged 中最后一个区间重叠,合并区间
            merged[-1][1] = max(merged[-1][1], interval[1])
    
    return merged

# 示例
intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
print(merge_intervals(intervals))  
# 输出: [[1, 6], [8, 10], [15, 18]]

时间复杂度:O(nlog⁡n)O(n \log n),其中 nn 是区间的数量。排序的时间复杂度是 O(nlog⁡n)O(n \log n),遍历区间的时间复杂度是 O(n)O(n)。


例题2:插入区间

题目描述: 给定一个区间列表 intervals 和一个新的区间 newInterval,请将新的区间插入到区间列表中,确保合并后的区间没有重叠。

解法

  1. newInterval 插入到适当的位置。
  2. 然后和已有的区间一起进行合并。

代码实现

def insert_interval(intervals, new_interval):
    # Step 1: 插入新区间并排序
    intervals.append(new_interval)
    intervals.sort(key=lambda x: x[0])
    
    merged = []
    for interval in intervals:
        # 如果 merged 为空或当前区间与 merged 中最后一个区间不重叠,则直接添加
        if not merged or merged[-1][1] < interval[0]:
            merged.append(interval)
        else:
            # 如果当前区间与 merged 中最后一个区间重叠,合并区间
            merged[-1][1] = max(merged[-1][1], interval[1])
    
    return merged

# 示例
intervals = [[1, 3], [6, 9]]
new_interval = [2, 5]
print(insert_interval(intervals, new_interval))
# 输出: [[1, 5], [6, 9]]

时间复杂度:O(nlog⁡n)O(n \log n),其中 nn 是区间的数量。插入新区间并排序的时间复杂度是 O(nlog⁡n)O(n \log n),合并区间的时间复杂度是 O(n)O(n)。


例题3:区间的非重叠部分

题目描述: 给定一组区间,请找到区间中不重叠的部分的总长度。即对于每一对区间,计算它们的非重叠部分。

解法

  1. 对区间进行合并。
  2. 合并后的区间的总长度就是合并后的区间的所有长度的和。

代码实现

def non_overlapping_length(intervals):
    # Step 1: 对区间进行排序
    intervals.sort(key=lambda x: x[0])
    
    merged = []
    total_length = 0
    for interval in intervals:
        # 如果 merged 为空或当前区间与 merged 中最后一个区间不重叠,则直接添加
        if not merged or merged[-1][1] < interval[0]:
            merged.append(interval)
            total_length += interval[1] - interval[0]
        else:
            # 如果当前区间与 merged 中最后一个区间重叠,合并区间
            total_length -= merged[-1][1] - merged[-1][0]  # 减去原先的长度
            merged[-1][1] = max(merged[-1][1], interval[1])  # 合并区间
            total_length += merged[-1][1] - merged[-1][0]  # 加上合并后的长度
    
    return total_length

# 示例
intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
print(non_overlapping_length(intervals))  
# 输出: 8

时间复杂度:O(nlog⁡n)O(n \log n),其中 nn 是区间的数量。排序的时间复杂度是 O(nlog⁡n)O(n \log n),遍历区间的时间复杂度是 O(n)O(n)。


总结:区间合并技巧

应用场景关键步骤描述
合并区间排序 -> 合并对区间进行排序并合并重叠区间
插入新区间插入新区间 -> 排序 -> 合并将新区间插入并进行合并
非重叠部分计算合并区间 -> 计算总长度对所有区间进行合并后计算非重叠部分的总长度
动态合并区间动态更新区间 -> 合并对实时更新的区间进行合并操作

区间合并是一个典型的排序和合并问题,最重要的是根据区间的起始位置进行排序,再根据合并的规则逐步合并区间。通过这种方式,可以高效地解决很多区间类问题。

<think>好的,用户想找关于区间合并例题或练习题。首先,我需要回忆一下区间合并的基本概念和应用场景。区间合并通常用于将重叠或相邻的区间合并成一个更大的区间,这在处理时间调度、区间覆盖等问题时非常有用。 接下来,我需要查看用户提供的引用资料。引用[2]提到合并区间和最大数,说明区间合并是排序算法的一种应用。引用[4]给出了一个具体的例子,输入是[[1,3],[2,6],[8,10],[15,18]],输出合并后的结果。引用[5]提到使用贪心算法来合并区间,通常的做法是先排序再合并。 用户需要的是例题或练习题,所以应该提供几个不同难度的例子,并附上解题思路和代码实现。比如,可以包括基础题如LeetCode 56,进阶题如插入新区间,以及变形题如计算合并后的区间长度总和。此外,用户可能需要Python的示例代码,因为之前的示例中有Python代码。 还需要注意格式要求,行内数学公式用$...$,独立公式用$$...$$,并且正确使用LaTeX语法。例如,区间可以写成$[a_i, b_i]$。同时,每个问题后面需要生成相关问题,并正确添加引用标识。 检查引用的来源,确保每个引用对应的内容准确。例如,引用[4]对应LeetCode 56题,引用[5]对应贪心算法的应用。在回答中引用这些内容时,需要在末尾添加对应的标识,如[^4]或[^5]。 最后,确保回答结构清晰,分点列出例题,每个例题包含问题描述、示例、解题思路和代码实现。代码部分需要用Python,并且按照格式要求使用代码块。同时,生成的相关问题要围绕区间合并的应用、优化和扩展题型展开。</think>### 区间合并算法详解与例题 区间合并的核心是通过排序和贪心策略,将重叠或相邻的区间合并为更大的区间。以下是具体示例和实现方法: --- #### **例题1:基础合并区间(LeetCode 56)** **问题描述** 给定一个区间集合 `intervals`,合并所有重叠的区间。 **示例输入与输出** 输入:$[[1,3],[2,6],[8,10],[15,18]]$ 输出:$[[1,6],[8,10],[15,18]]$ **解题思路** 1. **排序**:按区间左端点升序排列,使重叠区间连续。 2. **合并**:遍历排序后的区间,若当前区间左端点 ≤ 前一个区间的右端点,则合并为 $[\text{prev\_left}, \max(\text{prev\_right}, \text{current\_right})]$[^4]。 **Python实现** ```python def merge(intervals): if not intervals: return [] intervals.sort(key=lambda x: x[0]) # 按左端点排序 merged = [intervals[0]] for current in intervals[1:]: last = merged[-1] if current[0] <= last[1]: last[1] = max(last[1], current[1]) # 合并区间 else: merged.append(current) return merged ``` --- #### **例题2:插入并合并区间(LeetCode 57)** **问题描述** 在已排序的非重叠区间列表中插入一个新区间,合并后返回结果。 **示例输入与输出** 输入:$[[1,3],[6,9]]$,插入 $[2,5]$ 输出:$[[1,5],[6,9]]$ **解题思路** 1. **插入**:将新区间加入列表并重新排序。 2. **合并**:沿用基础合并方法。 **Python实现** ```python def insert(intervals, new_interval): intervals.append(new_interval) intervals.sort(key=lambda x: x[0]) return merge(intervals) # 复用例题1的合并函数 ``` --- #### **例题3:计算合并后的总长度** **问题描述** 给定区间列表,计算合并后所有区间覆盖的总长度。 **示例输入与输出** 输入:$[[1,4],[2,5],[7,10]]$ 输出:$8$(合并后为 $[1,5]$ 和 $[7,10]$,总长度 $4+3=7$) **解题思路** 1. **合并区间**:先合并所有重叠区间。 2. **累加长度**:对每个合并后的区间计算 $b_i - a_i$ 并求和[^2]。 **Python实现** ```python def total_covered_length(intervals): merged = merge(intervals) # 复用例题1的合并函数 return sum(end - start for start, end in merged) ``` --- ### **相关问题** 1. 如何优化区间合并的时间复杂度? 2. 区间合并算法在日程安排问题中的应用? 3. 如何处理包含离散点的区间合并问题? [^1]: 算法练习题--滑动窗口算法详细解析 : 合并区间、最大数 : LeetCode 56合并区间示例 : 贪心算法合并区间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值