区间的合并

给定 n个区间 [l_{i},r_{i}],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3]和 [2,6]可以合并为一个区间 [1,6]。

输入格式

第一行包含整数 n。

接下来 n行,每行包含两个整数 l和 r。

输出格式

共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围

1≤n≤100000,
-10^{9}l_{i}r_{i}10^{9}

输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;

vector<PII> segs;

void merge(vector<PII>& segs){//这里注意引用符号,关于引用的用法我前面有说过,这里就不说了。
    vector<PII> res;//定义装结果区间的vector数组res。
    sort(segs.begin(),segs.end());
    /*在操作之前,先将输入的一个个区间给排序,这里要注意,我们是用的vector<PII> segs;来存的,是pair
    <int,int>,相当于输入的{l,r}就是一个元素,数组里面有多少个元素,就说明有多少个区间,这一点
    我会在我写的博客里面细讲的。*/
    int st = -2e9,ed = -2e9;/*初始化定义开始值和结束值为-2e9,定义为-2e9是因为输入的是l,r两个,
    这里相当于定义的是无效值的感觉,说明此时还没有开始,区间里面还没有值。*/
    for(auto seg : segs){
        if(ed < seg.first){
            /*我的理解是:这个ed是当前操作区间的末尾点ed,而seg.first则是当前操作区间的下一个枚举区间
            ,当当前操作区间的末尾点ed小于下一个枚举区间的开头seg.first的时候,就说明当前操作区间
            与下一个枚举区间之间没有交集,既然没有交集,那就将当前操作区间放入结果vector数组res里面。
            */
            if(st != -2e9)  res.push_back({st,ed});//当前操作区间{st,ed}直接插入进去。
            /*刚开始我们初始化了st=-2e9,满足条件,要将当前操作区间放入结果数组里面的时候,要注意,
            不能让st等于初始值-2e9,不然会报错。*/
            st = seg.first,ed = seg.second;
            //将当前操作区间放入结果数组后,将st和ed两个更新为下一个枚举区间的st,ed的值,准备下一次操作
        }
        else ed = max(ed,seg.second);
   /*如果满足上面的条件,那就说明两个区间之间有交集,那么这个时候st是不动的,只需要将ed更新为两个区间
   中最大的那个ed值即可,就是求两个集合的并集。*/     
    }
    if(st != -2e9)   res.push_back({st,ed});
    /*注意,当遍历循环次数结束的时候,最后得到的那个区间是没办法加入到结果数组res里面的,所以这里
    判断,如果st不为初始值的化,那么就把此时的{st,ed}结果区间给插进去,就可以了。而且这个还有一个
    作用就是防止输入的区间是空的。*/
    segs = res;
    /*将得到的结果数组覆盖之前的segs数组,最后方便输出。所以这里可以看出来,res数组只是一个中间变量
    而已。*/
}


int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        int l,r;
        cin>>l>>r;
        segs.push_back({l,r});
        /*定义这个segs(vector)类型的是因为每一次输入的数都不一样,随着输入次数的变化。segs里面的
        内容也会随着变化,所以这种存变化的数据的就用可变数组vector来存。*/
    }
    merge(segs);
    /*输入之后就想着合并,注意,我们segs刚开始是存储的所有的输入的序列,为了输出和各方面的方便,我们也
    segs来作为结果输出,那么想做到这样就是在一个函数里面把结果给得到,然后把结果复制给segs,把segs
    原有的给覆盖,最后就可以输出了,就是下面的cout那句话了。*/
    cout<<segs.size()<<endl;
    /*res结果区间复制给segs区间,覆盖他,最后输出里面有几个区间元素就得到了结果了。*/
    
    return 0;
}

 注意事项:

1、

这句代码 sort(segs.begin(), segs.end()); 是用来对容器 segs 中的元素进行排序的。具体来说:

   segs 是一个存储区间的容器,比如一个 vector<pair<int, int>>

   sort(segs.begin(), segs.end()); 会对容器 segs 中的所有元素进行排序。

排序的细节

      如果 segs 是 vector<pair<int, int>>,那么 sort 函数会按照 pair 的第一个元素(即每个区间的起始位置 l)进行排序。如果第一个元素相同,则会按照第二个元素(即每个区间的结束位置 r)进行排序。

     这意味着,排序后的 segs 会按照区间的起始位置升序排列,如果起始位置相同,则按照结束位置升序排列。

示例

假设 segs 的内容是:

vector<pair<int, int>> segs = {{3, 5}, {1, 4}, {2, 6}};

经过 sort(segs.begin(), segs.end()); 后,segs 将变成:

{{1, 4}, {2, 6}, {3, 5}}

排序后的结果是按每个区间的起始位置从小到大排列的。如果两个区间的起始位置相同,则按结束位置排序。

相当于说一个区间就是一个元素,因为我们使用的就是pair<int,int>来存的,就是说我们每次输入的{l,r}就是一个元素,千万不要理解为每个数来排序,这样理解是错误的哦。

2、对于ed < seg.first这个判断条件的理解

       操作区间(Current Interval):通常表示你当前正在处理或操作的区间。这可能是一个动态的区间,随着程序的执行而不断变化。

       枚举区间(Enumerated Interval):这是你用来比较的固定区间,通常是从某些数据结构中提取出来的或者是预定义的。

ed < seg.first的含义

ed < seg.first 这一条件表示你正在将操作区间的结束点 ed 与枚举区间的起始点 seg.first 进行比较。这通常用于确定操作区间是否与枚举区间有重叠或者是否有关系。

      如果 ed < seg.first:这表明操作区间的结束点在枚举区间的开始点之前。这可能意味着当前的操作区间在时间上或者逻辑上完全在枚举区间的左侧,没有交集。

      如果操作区间和枚举区间有交集,则会有条件处理或者更新操作区间的逻辑。这是因为交集可能需要合并、分割或其他操作来正确处理数据。

ed 代表当前操作区间的结束点,而 seg.first 代表枚举区间的起始点。这种比较通常用于判断操作区间与枚举区间是否有重叠,进而决定如何处理这些区间的逻辑。

3、总结:

初始化 st 和 ed 为 -2e9 是为了表示当前没有有效的区间。

遍历区间并根据是否重叠或相邻来决定是否将区间添加到结果中。

处理最后一个区间是为了确保最后一个有效区间被包含在结果中。

4、是否可以省略 if (st != -2e9) res.push_back({st, ed});

不能省略。在处理不重叠的区间时,我们需要确保当前的区间被正确地添加到结果中。初始值 -2e9 的作用是标记“无效”状态,所以当 st 不等于 -2e9 时,说明我们已经有一个有效的区间需要被添加到结果中。

<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、付费专栏及课程。

余额充值