Leetcode合并区间

  1. 合并区间

以数组 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].

解法:
可以将给定的intervals数组中的数字看成是数组中的一些段。因为题目中没有说一定是排序的,所以可能会出现[8,10][2,4]的前面。所以可以先进行一个排序,按照每个区间的左端点进行排序。这样进行排序之后,一定是按照左端点进行递增的。但是右端点不一定是递增的。这是这题容易忽略的地方。就是说可能会出现这种情况:[1,10] [2,8]1,2固然是按照地址的顺序。但是,10,8 并不是。这个也关系到后面写代码。那么,在排完序之后,如果一个区间的左端点大于前一个区间的右端点,那么证明这两个区间没有联系,可以直接将前面区间加入结果中。唯一要注意的就是那些重叠的区间。重叠区间也简单,就是一旦判断到有重叠就将右端点一直向右扩张,直到发现一个不重叠的或者到了数组结尾。
代码:

class Solution {
    public int[][] merge(int[][] intervals) {
        // 先按照区间起始位置排序
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        // 遍历区间
        int[][] res = new int[intervals.length][2];
        int idx = -1;
        for (int[] interval: intervals) {
            // 如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,
            // 则不合并,直接将当前区间加入结果数组。
            if (idx == -1 || interval[0] > res[idx][1]) {
                res[++idx] = interval;
            } else {
                // 反之将当前区间合并至结果数组的最后区间
                res[idx][1] = Math.max(res[idx][1], interval[1]);
            }
        }
        return Arrays.copyOf(res, idx + 1);
    }
}

  1. 插入区间

给出一个无重叠的 ,按照区间起始端点排序的区间列表。

在列表中插入一个新的区间,你需要确保列表中的区间仍然 有序且不重叠(如果有必要的话,可以 合并区间)。

示例 1::
输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]
解释: 新区间[2,5] 与 [1,3]重叠,因此合并成为 [1,5]。

示例 2::
输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 新区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠,因此合并成为 [3,10]。

解法:
要返回的是二维数组,由于数组要指定长度,可以指定一个最大可能的长度,最后用Arrays.codyOf(int []source ,int lastIndex)方法来进行截取数组进行返回。
由于这个题已经说了按照左端点排序给出区间了,所以不用再去排序了。和上面一样,在那个要插入的区间的左端点左边的区间可以直接加入结果,因为没有重叠部分。那么这一部分的判断条件就是intervals[i][1] < newInterval[0] 。所以不满足这个条件的就一定不会再要加入的区间的左边,那么也就是可能会重叠。也可能是不会重叠,不会重叠的情况就是区间的左端点大于要插入区间的右端点。
所以,现在就要处理重叠部分。重叠部分的判断条件是intervals[i][0] <= newInterval[1]。这个判断条件很重要!!!已经包含了两个区间刚刚好接头的情况。
那么,处理完重叠部分,那么右边不重叠部分就可以直接加入结果了。所以这个题就是看成是一个数组,然后有一个区间要加入已经有的区间。只有那些重叠的区间在可能被影响,其它两侧不被影响的直接加入结果返回就行了。
完整代码如下:

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        int[][] res = new int[intervals.length + 1][2];
        int idx = 0;
        // 遍历区间列表:
        // 首先将新区间左边且相离的区间加入结果集
        int i = 0;
        while (i < intervals.length && intervals[i][1] < newInterval[0]) {
            res[idx++] = intervals[i++];
        }
        // 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,
        // 将最终合并后的新区间加入结果集
        while (i < intervals.length && intervals[i][0] <= newInterval[1]) {
            newInterval[0] = Math.min(intervals[i][0], newInterval[0]);
            newInterval[1] = Math.max(intervals[i][1], newInterval[1]);
            i++;
        }
        res[idx++] = newInterval;
        // 最后将新区间右边且相离的区间加入结果集
        while (i < intervals.length) {
            res[idx++] = intervals[i++];
        }

        return Arrays.copyOf(res, idx);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值