【LeetCode刷题】重叠区间问题

本文介绍了四个关于区间操作的算法问题,包括判断会议是否能安排、合并重叠区间、插入新区间和删除被覆盖区间。每个问题都提供了详细的题解和代码实现,涉及排序、比较和区间处理技巧。这些算法在处理时间规划和资源调度等问题时非常实用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跟着甜姨整理了这一类问题,没有固定套路,但需要找规律以及细心。

重叠区间

252,会议室,easy

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RyjkQOwu-1624517901590)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210624093942480.png)]

题解

实质是判断有没有重叠区间,将区间按照会议开始时间排序,然后遍历一遍即可。

代码

class Solution{
    public boolean canAttendMeetings(int[][] intervals){
        Arrays.sort(intervals, (v1, v2)->v1[0]-v2[0]);
        for(int i = 1; i < intervals.length; i++){
            if(intervals[i][0] < intervals[i - 1][1])
                return false;
        }
        return true;
    }
}
56,合并区间,medium

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dr9mCjyV-1624517901629)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210624094446342.png)]

题解

与上一题的区别在于要合并重叠的区间,还是从intervals的第一个元素开始遍历,最开始比较的对象为intervals[0][1],在遍历过程中不断更新,此对象的含义为上一个区间的末尾。即新的区间的开头比上一区间的末尾大,就不需要合并。

代码

class Solution {
    public int[][] merge(int[][] intervals) {
        if(intervals.length == 1) return intervals;
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        int flag = intervals[0][1];
        int[][] res = new int[intervals.length + 1][2];
        int idx = 0;
        res[0] = intervals[0];
        for(int i = 1; i < intervals.length; i++){
            if(intervals[i][0] <= flag){
                res[idx][1] = Math.max(res[idx][1], intervals[i][1]);
                flag = res[idx][1];
            }else{
                res[++idx] = intervals[i];
                flag = intervals[i][1];
            }
        }
        return Arrays.copyOf(res, idx + 1);
    }
}
57,插入区间,medium

在这里插入图片描述
在这里插入图片描述

题解

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

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

代码

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        int pL = newInterval[0];
        int pR = newInterval[1];
        int[][] res = new int[intervals.length + 1][2];
        int i = 0;
        //[[1,2],[3,5],[6,7],[8,10],[12,16]]
        //         4          8
        //[[1,2],[3,10],[12,16]]	
        int idx = 0;
        //无重叠部分
        while(i < intervals.length && intervals[i][1] < pL){
            res[idx++] = intervals[i++];
        }
        // 接着判断当前区间是否与新区间重叠,重叠的话就进行合并,直到遍历到当前区间在新区间的右边且相离,
        // 将最终合并后的新区间加入结果集 
        while(i < intervals.length && intervals[i][0] <= pR){
            pL = Math.min(intervals[i][0], pL);
            pR = Math.max(intervals[i][1], pR);
            i++;
        }
        res[idx++] = new int[]{pL, pR};
        while(i < intervals.length){
            res[idx++] = intervals[i++];
        }
        return Arrays.copyOf(res, idx);
    }
}
1288,删除被覆盖区间,medium

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XX831MIv-1624517901640)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210624111857877.png)]

题解

贪心

先按区间左边界升序排列,如果相等,按右区间降序排列(消除覆盖区间)

这样只需要更新一个右边界值即可

遍历区间,如果被覆盖,区间数-1;如果没有被覆盖,则更新新的边界值。

代码

class Solution {
    public int removeCoveredIntervals(int[][] intervals) {
        if(intervals.length == 1) return 1;
        Arrays.sort(intervals, (v1, v2) -> v1[0] == v2[0] ? v2[1] - v1[1] : v1[0] - v2[0]);
   
        int res = intervals.length;
        int r = intervals[0][1];
        for(int i = 1; i < intervals.length; i++){
            if(intervals[i][1] <= r){
                res--;
            }
            else r = Math.max(r, intervals[i][1]);
            
        }
        return res;
    }
}
228,汇总区间,easy

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IPB23pYw-1624517901643)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210624145404375.png)]

题解

对连续的数字按固定格式输出,那么双指针找到不连续的数字即可。

找到之后更新i = j + 1

在一个循环中判断一下双指针所指位置,如果相同则只添加一个元素。

代码

class Solution {
    public List<String> summaryRanges(int[] nums) {
        //双指针
        List<String> res = new ArrayList<>();
        if(nums.length == 0) return res;
        if(nums.length == 1){
            res.add(String.valueOf(nums[0]));
            return res;
        }
        int i = 0;
        for(int j = 0; j < nums.length; j++){
            //找到第一个不符合递增规则的,或者遍历完成
            if(j == nums.length - 1 || nums[j] + 1 != nums[j + 1]){
                String tmp = String.valueOf(nums[i]) + "->" + String.valueOf(nums[j]);
                if(nums[i] != nums[j])
                    res.add(tmp);
                else res.add(String.valueOf(nums[j]));
                i = j + 1;
            }
            
        }
        return res;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值