LeetCode 热题 100-----14.合并区间
一、题目详解首先我们用最直白的话把题目说清楚不用任何专业术语保证你一看就懂给你一个“区间数组”这个数组里的每一个元素都是一个“区间”——比如 [1,3]它代表从数字1到数字3的所有数包括1和3你可以把它想象成一根从1到3的线段。这些线段可能会有三种情况重叠比如 [1,3] 和 [2,6]线段[2,6]的开头2在[1,3]的中间两个线段叠在一起能拼成一根更长的线段 [1,6]端点相连比如 [1,4] 和 [4,5]第一个线段的结尾4和第二个线段的开头4连在一起也算“能合并”拼成 [1,5]完全不重叠比如 [8,10] 和 [15,18]两个线段离得很远没法合并只能保留原样。你的任务就是把所有能合并的线段重叠、端点相连都合并成一根长线段最后返回一个“没有重叠、没有相连”的线段数组并且这组线段要能完全覆盖原来所有的线段一个都不能漏。举个生活例子你有几张纸条分别写着1-3、2-6、8-10、15-18把重叠/相连的纸条粘在一起最后就剩下3张1-6、8-10、15-18这就是题目要的结果。二、必备前置知识在看解题思路和代码前必须先掌握这几个基础知识点——哪怕你完全没学过编程看完这部分也能跟上每一个点都配例子不跳步2.1 什么是“区间”和“区间数组”① 区间就是两个数字组成的“范围”格式是 [起点, 终点]比如 [1,3]起点是1终点是3且永远满足“起点 ≤ 终点”题目提示里明确说了 0 ≤ starti ≤ endi ≤ 104② 区间数组就是存放多个区间的“容器”比如题目里的输入 intervals [[1,3],[2,6],[8,10],[15,18]]这是一个“二维数组”可以理解成“数组里套数组”- Python里叫“列表套列表”写法是 List[List[int]]外面的大列表是“区间的集合”里面的每个小列表是“单个区间”- C里叫“vector套vector”写法是 vectorvectorint和Python的列表套列表功能完全一样都是用来存多个区间的。举例子intervals [[1,4],[4,5]]这个区间数组里有2个区间第一个区间是 [1,4]第二个是 [4,5]。2.2 二维数组列表的访问方式我们要操作区间就得先学会“拿到”某个区间以及某个区间的“起点”和“终点”两种语言的访问方式如下重点记代码里天天用① Python列表套列表- 拿到第i个区间intervals[i]i从0开始比如intervals[0]就是第一个区间- 拿到第i个区间的起点intervals[i][0]第一个[]是“第i个区间”第二个[]是“区间的第0个元素起点”- 拿到第i个区间的终点intervals[i][1]第二个[]是“区间的第1个元素终点”例子intervals [[1,3],[2,6]]intervals[0][0] 1第一个区间的起点intervals[1][1] 6第二个区间的终点。② Cvector套vector- 拿到第i个区间intervals[i]和Python一样i从0开始- 拿到第i个区间的起点intervals[i][0]写法和Python完全一样- 拿到第i个区间的终点intervals[i][1]写法和Python完全一样例子vectorvectorint intervals {{1,3},{2,6}}; intervals[0][0] 1intervals[1][1] 6。2.3 排序的作用核心中的核心这道题的关键一步就是“排序”为什么要排序举个例子你就懂假设输入是 [[4,7],[1,4]]示例3这两个区间是乱序的第一个区间起点4第二个起点1如果不排序我们先看[4,7]再看[1,4]容易判断错但如果我们按“区间的起点从小到大”排序这个数组就变成了 [[1,4],[4,7]]此时重叠/相连的区间就“挨在一起”了——我们只需要逐个检查相邻的两个区间就能判断是否能合并大大简化难度。总结排序的目的是让所有“可能能合并”的区间重叠、相连都变成相邻的这样我们只需要遍历一次就能完成所有合并不用来回找。补充Python和C都有现成的排序函数不用我们自己写后面代码里会详细讲怎么用。2.4 容器的基本操作存结果用我们需要一个“新容器”来存合并后的区间这个容器也是二维数组列表/vector常用操作如下① Python列表创建空列表merged []merged就是我们存结果的容器往列表里加元素加一个区间merged.append(区间)比如 merged.append([1,3])此时merged就变成了 [[1,3]]取列表的最后一个元素最后一个合并好的区间merged[-1]比如merged是 [[1,6],[8,10]]merged[-1]就是 [8,10]修改列表最后一个元素的终点merged[-1][1] 新终点比如merged[-1]是 [1,3]执行 merged[-1][1] 6就变成了 [1,6]。② Cvector创建空vectorvectorvectorint merged;和Python的空列表一样往vector里加元素merged.push_back(区间)比如 merged.push_back({1,3})此时merged就有一个区间 [1,3]取vector的最后一个元素merged.back()比如merged是 {{1,6},{8,10}}merged.back()就是 {8,10}判断vector是否为空merged.empty()为空返回true不为空返回false用来判断是否是第一个区间修改最后一个元素的终点merged.back()[1] 新终点和Python的 merged[-1][1] 用法一样。2.5 循环遍历逐个检查区间我们需要逐个检查每个原始区间判断它能不能和“已经合并好的最后一个区间”合并这就需要用到“循环遍历”① Python用 for 循环遍历区间数组写法是 for current in intervals: 其中current就是“当前正在检查的区间”例子intervals [[1,3],[2,6]]循环第一次current是 [1,3]第二次是 [2,6]。② C用 for 循环遍历写法是 for (auto current : intervals) 其中auto是“自动识别类型”不用我们写vectorint是“引用”相当于直接操作原区间不复制更高效current也是“当前正在检查的区间”。2.6 补充max函数取两个数的最大值合并区间时需要取“两个区间终点的最大值”作为合并后区间的终点比如 [1,3] 和 [2,6]终点分别是3和6max(3,6)6所以合并后终点是6。① Pythonmax(a, b)直接用比如 max(3,6) → 6② Cmax(a, b)需要包含头文件 #include algorithm后面代码会包含比如 max(3,6) → 6。三、解题思路由易到难暴力解法→最优解法我们先讲“暴力解法”容易理解思路简单再讲“最优解法”面试/刷题常用效率高对比两者的区别让你明白为什么最优解法更好。3.1 暴力解法思路简单效率低3.1.1 核心思路4步暴力解法的核心是“两两比较”把所有能合并的区间都合并直到没有可合并的区间为止先给区间数组按“起点升序”排序和最优解法一样排序是基础创建一个新容器把原始区间数组的所有元素都放进去相当于“待合并的区间”循环遍历新容器拿当前区间和它后面的所有区间比较如果当前区间和后面某个区间重叠/相连 → 合并这两个区间把合并后的区间放回当前位置删除后面那个区间如果不重叠 → 继续比较下一个。重复步骤3直到遍历完所有区间没有可合并的为止最后返回这个新容器。3.1.2 暴力解法的问题因为要“两两比较”比如有n个区间最坏情况下所有区间都不重叠需要比较n*(n-1)/2次时间复杂度是 O(n²)n平方当n很大时比如题目提示的n104会很慢所以面试时不推荐用但可以通过它理解“合并”的逻辑。3.2 最优解法排序一次遍历效率高这是面试和刷题的“标准答案”时间复杂度最低代码最简单也是我们重点讲解的解法核心思路是“排序后只和最后一个合并好的区间比较”不用两两比较。3.2.1 核心思路排序将所有区间按“起点从小到大”排序和暴力解法第一步一样核心目的是让重叠/相连的区间相邻初始化创建一个空容器merged用来存合并后的区间一开始是空的没有任何合并好的区间遍历判断核心步骤逐个取出原始区间current和merged里“最后一个合并好的区间”last比较如果merged是空的还没有任何合并好的区间→ 直接把current加进去第一个区间没有可合并的对象如果last的终点 ≥ current的起点 → 重叠/相连需要合并把last的终点改成“last的终点和current的终点的最大值”比如last是[1,3]current是[2,6]last的终点改成max(3,6)6合并成[1,6]如果last的终点 current的起点 → 不重叠直接把current加到merged里和前面的区间都不重叠作为新的合并区间返回结果遍历完所有原始区间后merged里就是“没有重叠、完全覆盖所有原始区间”的结果返回merged即可。3.2.2 最优解法的优势排序的时间复杂度是 O(n log n)n乘以log n遍历的时间复杂度是 O(n)只走一遍整体时间复杂度是 O(n log n)比暴力解法的 O(n²) 快很多适合n很大的情况比如题目中的104个区间也是面试中必须掌握的解法。3.2.3 思路演示结合示例1跟着算示例1输入intervals [[1,3],[2,6],[8,10],[15,18]]排序已经是按起点升序不用变 → [[1,3],[2,6],[8,10],[15,18]]初始化merged []遍历第一个区间 current [1,3]merged是空的直接加进去 → merged [[1,3]]遍历第二个区间 current [2,6]last [1,3]last[1]3≥ current[0]2→ 合并last[1] max(3,6)6 → merged [[1,6]]遍历第三个区间 current [8,10]last [1,6]last[1]6 current[0]8→ 不合并加进去 → merged [[1,6],[8,10]]遍历第四个区间 current [15,18]last [8,10]last[1]10 current[0]15→ 不合并加进去 → merged [[1,6],[8,10],[15,18]]返回merged就是示例1的输出。四、Python 完整代码含主函数详细注释运行流程测试用例以下代码可直接复制运行本地Python环境、LeetCode均可每一句都有注释并且包含“主函数”——可以测试题目给的3个示例还能自定义输入打印输入和输出能清晰看到代码运行过程。4.1 完整代码最优解法面试推荐# 导入类型提示LeetCode默认自带本地Python运行时没有这句话会报警告但不影响运行 from typing import List # 定义Solution类LeetCode固定格式必须有这个类里面放解题函数 class Solution: # 定义merge函数题目要求的函数名参数是intervals类型是List[List[int]]返回值也是List[List[int]] def merge(self, intervals: List[List[int]]) - List[List[int]]: # 第一步按区间的【起点】从小到大排序Python默认对二维列表按第一个元素排序完美符合我们的需求 # 比如输入[[4,7],[1,4]]排序后变成[[1,4],[4,7]] intervals.sort() # 第二步初始化结果容器merged用来存合并后的区间一开始是空列表 merged [] # 第三步遍历每一个原始区间current就是当前正在检查的区间 for current in intervals: # 情况1merged是空的还没有任何合并好的区间→ 直接把当前区间加进去 if not merged: merged.append(current) else: # 情况2merged不是空的取出merged里最后一个合并好的区间last last merged[-1] # 判断last的终点 ≥ current的起点 → 重叠/相连需要合并 if last[1] current[0]: # 合并逻辑把last的终点改成“last的终点和current的终点的最大值” # 比如last是[1,3]current是[2,6]max(3,6)6last变成[1,6] merged[-1][1] max(last[1], current[1]) else: # 情况3不重叠直接把当前区间加到merged里 merged.append(current) # 第四步返回合并后的结果 return merged # 主函数核心用来测试代码可以在这里修改输入查看运行结果 if __name__ __main__: # 1. 创建Solution类的实例必须创建实例才能调用里面的merge函数 solution Solution() # 2. 测试题目给出的3个示例 print(*50) print(测试示例1) intervals1 [[1,3],[2,6],[8,10],[15,18]] # 示例1输入 result1 solution.merge(intervals1) # 调用merge函数得到结果 print(f输入{intervals1}) print(f输出{result1}) # 预期输出[[1,6],[8,10],[15,18]] print(*50) print(测试示例2) intervals2 [[1,4],[4,5]] # 示例2输入 result2 solution.merge(intervals2) print(f输入{intervals2}) print(f输出{result2}) # 预期输出[[1,5]] print(*50) print(测试示例3) intervals3 [[4,7],[1,4]] # 示例3输入 result3 solution.merge(intervals3) print(f输入{intervals3}) print(f输出{result3}) # 预期输出[[1,7]] # 3. 自定义测试用例可以自己改这里的输入测试不同情况 print(*50) print(自定义测试用例1单个区间边界情况) intervals4 [[5,7]] # 自定义输入只有1个区间 result4 solution.merge(intervals4) print(f输入{intervals4}) print(f输出{result4}) # 预期输出[[5,7]] print(*50) print(自定义测试用例2完全重叠的区间) intervals5 [[1,5],[2,3],[4,6]] # 自定义输入3个区间全部重叠 result5 solution.merge(intervals5) print(f输入{intervals5}) print(f输出{result5}) # 预期输出[[1,6]] print(*50) print(自定义测试用例3乱序且多重叠区间) intervals6 [[3,5],[1,2],[4,7],[6,8]] # 自定义输入乱序多个重叠 result6 solution.merge(intervals6) print(f输入{intervals6}) print(f输出{result6}) # 预期输出[[1,2],[3,8]]4.2 代码运行流程拆解跟着走一步都不跳我们以“自定义测试用例3”为例拆解代码运行的每一步让你清楚每一句代码的作用自定义测试用例3输入intervals6 [[3,5],[1,2],[4,7],[6,8]]运行 intervals.sort() → 按起点排序排序后变成 [[1,2],[3,5],[4,7],[6,8]]merged [] → 初始化空列表第一次循环current [1,2]merged是空的 → 执行 merged.append([1,2]) → merged [[1,2]]第二次循环current [3,5]merged不是空的last merged[-1] [1,2]判断 last[1]2≥ current[0]3→ 2 3不成立执行 merged.append([3,5]) → merged [[1,2],[3,5]]第三次循环current [4,7]last [3,5]判断 last[1]5≥ current[0]4→ 成立重叠merged[-1][1] max(5,7) 7 → merged变成 [[1,2],[3,7]]第四次循环current [6,8]last [3,7]判断 last[1]7≥ current[0]6→ 成立重叠merged[-1][1] max(7,8) 8 → merged变成 [[1,2],[3,8]]循环结束返回 merged → [[1,2],[3,8]]和预期输出一致。4.3 Python 暴力解法代码可选理解用from typing import List class Solution: def merge(self, intervals: List[List[int]]) - List[List[int]]: # 第一步排序暴力解法也需要排序否则没法两两比较 intervals.sort() # 第二步把原始区间全部放进merged作为待合并的容器 merged intervals.copy() # 复制一份不修改原始输入 # 第三步两两比较合并重叠区间i从0开始遍历到倒数第二个区间 i 0 while i len(merged) - 1: # 当前区间 current merged[i] # 下一个区间和current比较 next_interval merged[i1] # 判断是否重叠/相连 if current[1] next_interval[0]: # 合并两个区间起点是current的起点终点是两者终点的最大值 merged[i] [current[0], max(current[1], next_interval[1])] # 删除下一个区间已经合并到current里了 del merged[i1] # 注意删除后i不用1因为下一个区间变成了原来的i2需要重新比较当前i else: # 不重叠i1比较下一对 i 1 return merged # 主函数和最优解法的主函数一样可直接测试 if __name__ __main__: solution Solution() intervals [[3,5],[1,2],[4,7],[6,8]] print(f输入{intervals}) print(f输出{solution.merge(intervals)}) # 输出[[1,2],[3,8]]五、C 完整代码含主函数详细注释运行流程测试用例以下代码可直接复制到C编译器比如Dev-C、VS运行同样包含主函数、测试用例每一句都有注释和Python代码逻辑完全一致只是语法不同可以对照Python代码看更容易理解。5.1 完整代码最优解法面试推荐#include iostream // 用于输入输出打印测试用例 #include vector // 用于使用vector容器存区间数组 #include algorithm // 用于使用sort排序函数和max函数 using namespace std; // 简化代码不用每次都写std:: // 定义Solution类LeetCode固定格式 class Solution { public: // 定义merge函数题目要求的函数参数是vectorvectorint intervals引用传递更高效 // 返回值是vectorvectorint即合并后的区间数组 vectorvectorint merge(vectorvectorint intervals) { // 第一步按区间起点升序排序 // sort函数的参数容器的起始迭代器、结束迭代器默认按第一个元素升序排序 sort(intervals.begin(), intervals.end()); // 第二步初始化结果容器merged空vector vectorvectorint merged; // 第三步遍历每一个原始区间auto current自动识别类型引用传递 for (auto current : intervals) { // 情况1merged为空没有合并好的区间直接添加当前区间 if (merged.empty()) { merged.push_back(current); } else { // 情况2merged不为空取出最后一个合并好的区间引用传递修改会直接生效 auto last merged.back(); // 判断last的终点 ≥ current的起点 → 重叠/相连合并 if (last[1] current[0]) { // 合并逻辑更新last的终点为两者的最大值 last[1] max(last[1], current[1]); } else { // 情况3不重叠直接添加当前区间 merged.push_back(current); } } } // 第四步返回合并后的结果 return merged; } }; // 主函数测试代码可修改输入 int main() { // 1. 创建Solution类的实例 Solution solution; // 2. 测试题目给出的3个示例 cout endl; cout 测试示例1 endl; vectorvectorint intervals1 {{1,3},{2,6},{8,10},{15,18}}; // 示例1输入 vectorvectorint result1 solution.merge(intervals1); // 调用merge函数 cout 输入; // 打印输入的区间数组循环遍历打印 for (int i 0; i intervals1.size(); i) { cout [ intervals1[i][0] , intervals1[i][1] ]; if (i ! intervals1.size() - 1) cout ,; } cout endl; cout 输出; // 打印结果 for (int i 0; i result1.size(); i) { cout [ result1[i][0] , result1[i][1] ]; if (i ! result1.size() - 1) cout ,; } cout endl; cout endl; cout 测试示例2 endl; vectorvectorint intervals2 {{1,4},{4,5}}; vectorvectorint result2 solution.merge(intervals2); cout 输入; for (int i 0; i intervals2.size(); i) { cout [ intervals2[i][0] , intervals2[i][1] ]; if (i ! intervals2.size() - 1) cout ,; } cout endl; cout 输出; for (int i 0; i result2.size(); i) { cout [ result2[i][0] , result2[i][1] ]; if (i ! result2.size() - 1) cout ,; } cout endl; cout endl; cout 测试示例3 endl; vectorvectorint intervals3 {{4,7},{1,4}}; vectorvectorint result3 solution.merge(intervals3); cout 输入; for (int i 0; i intervals3.size(); i) { cout [ intervals3[i][0] , intervals3[i][1] ]; if (i ! intervals3.size() - 1) cout ,; } cout endl; cout 输出; for (int i 0; i result3.size(); i) { cout [ result3[i][0] , result3[i][1] ]; if (i ! result3.size() - 1) cout ,; } cout endl; // 3. 自定义测试用例可修改 cout endl; cout 自定义测试用例1单个区间 endl; vectorvectorint intervals4 {{5,7}}; vectorvectorint result4 solution.merge(intervals4); cout lt;lt; 输入; for (int i 0; i intervals4.size(); i) { cout [ intervals4[i][0] , intervals4[i][1] ]; if (i ! intervals4.size() - 1) cout ,; } cout endl; cout lt;lt; 输出; for (int i 0; i result4.size(); i) { cout [ result4[i][0] , result4[i][1] ]; if (i ! result4.size() - 1) cout ,; } cout endl; cout endl; cout 自定义测试用例2完全重叠区间 endl; vectorvectorint intervals5 {{1,5},{2,3},{4,6}}; vectorvectorint result5 solution.merge(intervals5); cout 输入; for (int i 0; i intervals5.size(); i) { cout [ intervals5[i][0] , intervals5[i][1] ]; if (i ! intervals5.size() - 1) cout ,; } cout endl; cout 输出; for (int i 0; i result5.size(); i) { cout [ result5[i][0] , result5[i][1] ]; if (i ! result5.size() - 1) cout ,; } cout endl; return 0; // 主函数结束返回0表示运行成功 }5.2 代码运行流程拆解对照Python易懂同样以“自定义测试用例2完全重叠区间”为例输入 intervals5 {{1,5},{2,3},{4,6}}拆解运行步骤运行 sort(intervals.begin(), intervals.end()) → 排序后还是 [[1,5],[2,3],[4,6]]已经按起点升序merged 初始化为空 vector第一次遍历current {1,5}merged.empty() → true空执行 merged.push_back(current) → merged {{1,5}}第二次遍历current {2,3}merged不为空last merged.back() {1,5}判断 last[1]5≥ current[0]2→ 成立合并last[1] max(5,3) 5 → merged还是 {{1,5}}第三次遍历current {4,6}last {1,5}判断 last[1]5≥ current[0]4→ 成立合并last[1] max(5,6) 6 → merged变成 {{1,6}}遍历结束返回 merged → {{1,6}}和预期输出一致。5.3 C 暴力解法代码可选理解用#include iostream #include vector #include algorithm using namespace std; class Solution { public: vectorvectorint merge(vectorvectorint intervals) { // 第一步排序 sort(intervals.begin(), intervals.end()); // 第二步复制原始区间到merged作为待合并容器 vectorvectorint merged intervals; // 第三步两两比较合并重叠区间 int i 0; while (i merged.size() - 1) { vectorint current merged[i]; vectorint next_interval merged[i1]; if (current[1] next_interval[0]) { // 合并区间 merged[i] {current[0], max(current[1], next_interval[1])}; // 删除下一个区间erase函数参数是迭代器merged.begin() i1 是下一个区间的位置 merged.erase(merged.begin() i 1); } else { i; } } return merged; } }; // 主函数测试 int main() { Solution solution; vectorvectorint intervals {{3,5},{1,2},{4,7},{6,8}}; vectorvectorint result solution.merge(intervals); cout 输入; for (int i 0; i intervals.size(); i) { cout [ intervals[i][0] , intervals[i][1] ]; if (i ! intervals.size() - 1) cout ,; } cout endl; cout 输出; for (int i 0; i result.size(); i) { cout [ result[i][0] , result[i][1] ]; if (i ! result.size() - 1) cout ,; } cout endl; return 0; }六、复杂度分析6.1 最优解法复杂度重点记时间复杂度O(n log n)排序的时间O(n log n)这是排序的固定时间复杂度比如n104log n≈17n log n≈1700很快遍历的时间O(n)只遍历一次所有区间n个区间就走n步整体时间由排序决定所以是 O(n log n)效率很高能处理题目中104个区间的最大情况。空间复杂度O(n)我们用了一个merged容器来存结果最坏情况下所有区间都不重叠merged的大小和原始区间数组一样都是n所以空间复杂度是O(n)如果不算存结果的容器排序本身需要的空间是O(1)Python的sort是原地排序C的sort也是原地排序。6.2 暴力解法复杂度时间复杂度O(n²)两两比较最坏情况下要比较n*(n-1)/2次n104时就是104*103/2≈5356次比最优解法慢很多空间复杂度O(n)和最优解法一样存结果需要O(n)空间。七、常见问题注意事项避坑坑1忘记排序 → 会导致重叠区间不相邻合并失败比如示例3不排序的话[[4,7],[1,4]]会判断成不重叠返回原数组错误坑2合并时只改起点不改终点 → 合并区间的核心是“取终点的最大值”比如[1,3]和[2,6]只改起点会变成[1,3]错误坑3把“端点相连”当成不重叠 → 题目明确说明[1,4]和[4,5]可以合并所以判断条件是“last[1] ≥ current[0]”不是“last[1] current[0]”坑4C忘记包含头文件 → 比如忘记包含algorithm会导致sort函数、max函数报错忘记包含vector会导致vector容器无法使用忘记包含iostream会导致cout、cin无法使用解决方法直接复制代码中的3个头文件不要遗漏坑5Python中修改merged[-1]时出错 → 比如误写为merged[1][1]这里要注意merged[-1]才是“最后一个合并好的区间”merged[1]是固定的第二个区间当merged只有1个区间时merged[1]会报错一定要用merged[-1]坑6忽略“空区间数组”边界情况 → 比如输入intervals []空数组没有任何区间此时merged也是空的直接返回即可代码无需额外修改当前代码已兼容merged.empty()会直接成立不执行后续操作返回空列表/vector坑7Python中用“intervals intervals.sort()” → 错误Python的sort()方法是“原地排序”执行后返回None正确写法是直接写intervals.sort()不要赋值给原变量否则intervals会变成None后续遍历会报错坑8C中遍历用“auto current”而非“auto current” → 不用引用的话会复制每个区间虽然不影响结果但效率更低尤其是区间数量较多时推荐用auto current引用传递坑9合并后忘记返回结果 → 代码最后一定要return merged否则函数会返回空值导致测试用例输出错误坑10容易混淆“区间的起点和终点” → 记住区间[start, end]start是第一个元素index0end是第二个元素index1不要写反比如把current[0]当成终点current[1]当成起点会导致判断完全错误。八、总结必看快速掌握核心排序是前提必须按区间“起点”从小到大排序让重叠/相连的区间相邻这是所有解法的基础这道题的核心非常简单记住3句话就能轻松搞定所有情况哪怕是也能快速上手代码是模板Python和C的最优解法代码可以直接记下来面试时遇到类似题目稍作修改就能用比如区间按终点排序、合并区间去重等变种题。合并是核心遍历所有区间只和“最后一个合并好的区间”比较重叠/相连就合并取终点最大值不重叠就新增。