这是我参与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);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥