Leetcode重叠区间、合并区间、插入区间

区间操作:重叠判断、合并与插入

一、判断区间是否重叠

题目描述:

力扣 252. 会议室
难度:Easy

给定一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,请你判断一个人是否能够参加这里面的全部会议。

示例 1::
输入: intervals = [[0,30],[5,10],[15,20]] 
输出: false
解释: 存在重叠区间,一个人在同一时刻只能参加一个会议。

示例 2::
输入: intervals = [[7,10],[2,4]] 
输出: true
解释: 不存在重叠区间。

代码:

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;
    }

思路:

一个人在同一时刻不能参加两次会议,即判断是否存在重叠区域,可以先对二维数组进行排序,然后遍历判断,后一个数组的开始时间是否早于当前数组的结束时间,是则出现重叠,return false;

否之完全遍历无重叠,返回True。

二、合并区间

题目描述:

力扣 56. 合并区间
难度:Medium

给出一个区间的集合,请合并所有重叠的区间。

示例 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] 可被视为重叠区间。

代码:

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

思路:

根据上一题心得,这一题加了一个合并的要求,所以在我们上一题返回的条件那做一个合并的处理就好了

首先可以先排序好整个二维数组,初始化返回数组res[0] = intervals[0];然后遍历每个子数组

注意,此时res存的是最初的结果,现在将每个子数组的起始值与res的结尾值比较(采用两个指针,idx指向res,i指向子数组),如果子数组的起始值比res的结尾值还要小,则出现重叠了

则res[idx][0] = Math.max(res[idx][0], interval[1]);

ps:这里可能会想到,如果多个需要合并呢?这里其实多个也不影响,因为idx始终指向这当前位置的,如果一直符合合并的条件,idx是一直指向当前位置的,循环会一直合并下去。。。

否之idx++;然后将子数组插入res

idx++;
res[idx] = interval;
最后返回就好啦,这里为什么是idx+1 是因为idx是索引,他是比长度要小1的,所以代表长度的话需要+1
return Arrays.copyOf(res, idx+1);

三、插入区间

题目描述:

57. 插入区间
难度:Medium

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

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

示例 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]。

代码:

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];
            i++;
            idx++;
        }
        // 前面已经判断完了所有比新插入区间起始点小的区间
        // 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,
        // 将最终合并后的新区间加入结果集
        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];
            i++;
            idx++;
        }

        return Arrays.copyOf(res, idx);
    }

思路:

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

  1. 首先将新区间左边且相离的区间加入结果集(遍历时,如果当前区间的结束位置小于新区间的开始位置,说明当前区间在新区间的左边且相离);

  2. 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,将最终合并后的新区间加入结果集;

  3. 最后将新区间右边且相离的区间加入结果集。

注意:

说人话就是你插入区间,万一没有合并情况的话用length就不够了,所以需要预先+1;

在给定的代码中,int[][] res = new int[intervals.length + 1][2];

语句初始化了一个二维整数数组res,其长度为intervals.length + 1

这是因为在插入新的区间时,存在两种情况:

  1. 新的区间与已有的区间不重叠,因此需要将新的区间单独作为一个区间加入结果集。
  2. 新的区间与已有的区间存在重叠,因此需要将重叠的区间进行合并,最终加入结果集。

为了确保结果集res能够容纳所有的区间,无论是否需要合并,将其初始化长度设置为intervals.length + 1,即比原始区间列表的长度多1。

这样做的好处是在处理区间合并时,无需频繁调整数组大小或创建新的数组。通过事先分配足够的空间,可以有效地处理所有情况并避免数组溢出或内存错误。

在遍历区间列表时,将新的区间插入到结果集的最后一个位置(res[idx++] = newInterval;),因此需要预留一个额外的位置来存储新的区间。

初始化长度为intervals.length + 1是为了确保结果集res足够大,可以容纳所有的区间,并在最后一个位置存储新的区间。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值