这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
前言
力扣第五十六题 合并区间
如下所示:
以数组 intervals
表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 1:
输入: intervals = [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入: intervals = [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
一、思路
合并区间
这一题中对 重叠区间
的定义为: 如果有 startj >= endi
则表示 i
和 j
两个区间有重叠,如 [2, 5]
和 [3, 6]
会有重叠部分。
题目中的 区间集合
不一定是按从左到右依次排列的,这对于合并重叠的区间会十分的困难。
所以我们第一步就是将 区间集合
按照 左边界升序排列,例如 [[5, 6], [1, 3], [2, 4]]
按照左边界升序后就变为了 [[1, 3], [2, 4], [5, 6]]
对于每个区间来说,它有可能是左边界重叠或右边界重叠。如果不将区间排序的话,就需要对每一个区间的左右边界判断是否重叠,还要判断是否会与新合并后的区间重合,这会大大增加算法的时间复杂度。
第二步就比较容易了,只需要遍历所有的区间,并判断相邻的两个区间是否重叠,如果重叠就合并,如 [[1, 3], [2, 4]]
这两个区间有重叠,则合并为 [1, 4]
综上所述,实现的思路总共分为两步:
- 按左边界升序排列
- 遍历并合并相邻的重叠区间
举个例子
此处以示例1中的 intervals = [[1,3],[2,6],[8,10],[15,18]]
作为例子
int[] pre:表示相邻的前一个区间
i=0
时,pre = [1, 3]
i=1
时,发现pre[1] > intervals[1][0],即 3 > 2
,此时合并两个区间pre = [1, 6]
i=2
时,发现pre[1] < intervals[1][0],即 6 < 8
,说明不会重叠,记录结果[1, 6]
,并更新pre
为当前区间pre = [8, 10]
i=3
时,发现pre[1] < intervals[1][0],即 10 < 15
,说明不会重叠,记录结果[8, 10]
,并更新pre
为当前区间pre = [15, 18]
- 遍历结束,返回存储的结果集即可
二、实现
实现代码
实现代码与思路中基本保持一致,略有改动的地方就是会在遍历结束后记录最后一个区间
public int[][] merge(int[][] intervals) {
int[][] ret = new int[intervals.length][];
// 间隔数组按照左端升序(冒泡)
Arrays.sort(intervals, Comparator.comparingInt(v -> v[0]));
int[] pre = intervals[0];
int index = 0;
for (int i=1; i<intervals.length; i++) {
if (intervals[i][0] > pre[1]){ // 如果当前区间的左边界大于前者的右边界则为不重叠
ret[index] = pre; // 保存结果
index++;
pre = intervals[i];
} else if (intervals[i][1] > pre[1]) { // 重叠且右边界溢出
pre[1] = intervals[i][1];
}
}
ret[index] = pre; // 保存最后一个分组
return Arrays.copyOf(ret, index + 1);
}
测试代码
public static void main(String[] args) {
int[][] nums = {{1,3},{2,6},{8,10},{15,18}};
int[][] nums1 = {{1,3}};
new Number56().merge(nums);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥