重叠区间、合并区间、插入区间问题详解

判断区间是否重叠

题目链接

252.合并区间

给定一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,请你判断一个人是否能够参加这里面的全部会议。
示例 1:
输入: intervals = [[0,30],[5,10],[15,20]]
输出: false
解释: 存在重叠区间,一个人在同一时刻只能参加一个会议。
示例 2:
输入: intervals = [[7,10],[2,4]]
输出: true
解释: 不存在重叠区间。

思路

因为一个人在同一时刻只能参加一个会议,因此题目实质是判断是否存在重叠区间,这个简单,将区间按照会议开始时间进行排序,然后遍历一遍判断即可。

代码

class Solution {
    public boolean canAttendMeetings(int[][] intervals) {
        // 将区间按照会议开始实现升序排序
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        // 遍历会议,如果下一个会议在前一个会议结束之前就开始了,返回 false。
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] < intervals[i - 1][1]) {
                return false;
            }
        }
        return true;
    }
}

合并区间

题目链接

56. 合并区间

以数组 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] 可被视为重叠区间。

思路

和上一题一样,首先对区间按照起始端点进行升序排序,然后逐个判断当前区间是否与前一个区间重叠,如果不重叠的话将当前区间直接加入结果集,反之如果重叠的话,就将当前区间与前一个区间进行合并。

代码

class Solution {
    public int[][] merge(int[][] intervals) {

        // 按第一列升序排列
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);

        int[][] res = new int[intervals.length][2];
        int index = -1;

        // 使用index = -1来判断result空
        for (int[] interval : intervals){
            if (index == -1 || interval[0] > res[index][1]){
                index++;
                res[index][0] = interval[0];
                res[index][1] = interval[1];
            }else{
                res[index][1] = Math.max(res[index][1], interval[1]);
            }
        }

        return Arrays.copyOf(res, index + 1);
    }
}

插入区间

题目链接

57. 插入区间

思路1

将新区间加入到原始区间集合中并排序,之后按合并区间的方法做就行。

代码1

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {

        int[][] res = new int[intervals.length + 1][2];
        int index = -1;
        int[][] new_intervals = new int[res.length][2];
        System.arraycopy(intervals, 0, new_intervals, 0, intervals.length);
        new_intervals[intervals.length] = newInterval;

        Arrays.sort(new_intervals, (v1, v2) -> v1[0] - v2[0]);

        for (int[] interval : new_intervals){
            if (index == -1 || res[index][1] < interval[0]){
                index++;
                res[index] = interval;
            }else{
                res[index][1] = Math.max(res[index][1], interval[1]);
            }
        }

        return Arrays.copyOf(res, index + 1);
    }
}

思路2

本题中的区间已经按照起始端点升序排列,因此我们直接遍历区间列表,寻找新区间的插入位置即可。具体步骤如下:

  1. 首先将新区间左边且相离的区间加入结果集(遍历时,如果当前区间的结束位置小于新区间的开始位置,说明当前区间在新区间的左边且相离);
  2. 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,将最终合并后的新区间加入结果集;
  3. 最后将新区间右边且相离的区间加入结果集。

代码2


posted @ 2022-12-31 11:26  Frodo1124  阅读(158)  评论(2编辑  收藏  举报