56、57、合并区间

  1. 56、合并区间
    1. 示例 1:
    2. 示例 2:
  2. 思路 1
    1. 代码实现
  3. 57、插入区间
    1. 示例 1:
    2. 示例 2:
  4. 思路
  5. 代码

56、合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

链接:https://leetcode-cn.com/problems/merge-intervals

提示:

  • $1 <= intervals.length <= 10^4$
  • intervals[i].length == 2
  • $0 <= start_i <= end_i <= 10^4$

思路 1

  • 先排个序,构造数据类,定义比较器,调用系统排序方法
  • 遍历一遍
    • 如果最后一个元素与当前元素相交,合并区间,取最大的终点
    • 如果不相交,作为一个新的区间加入到列表中

代码实现

$T_n = O(nlogn) S_n=O(1)$
面向对象编程。

class Solution {
    // 设计区间类
    class Interval{
        public int start;
        public int end;
        public Interval(int s,int e){
            this.start = s;
            this.end = e;
        }
        
        public Interval(Interval i) {
            this.start = i.start;
            this.end = i.end;
        }
    }
    // 自定义比较器
    public class IntervalComparetor implements Comparator<Interval> {
        @Override
        public int compare(Interval a,Interval b) {
            return a.start < b.start ? -1 : a.start == b.start ? 0 : 1;
        }
    }
    
    // 合并算法
    public List<Interval> merge(List<Interval> intervals) {
        // 先排序
        Collections.sort(intervals,new IntervalComparetor());
        // 结果集合
        LinkedList<Interval> res = new LinkedList<Interval>();
        
        Interval interval = new Interval(intervals.get(0).start,intervals.get(0).end);
        // 由于已经排好序,只要将后面的区间于合并好的最后一个区间进行比对就行了
        for (Interval i : intervals) {
            // 列表为空 或者 最后一个元素的终点小于当前区间的起点
            if (res.isEmpty() || res.getLast().end < i.start) {
                res.add(i);// 加入新的区间
            } else {
                // 更新最后一个区间的结束位置
                res.getLast().end = Math.max(res.getLast().end,i.end);// 合并区间
            }
        }
        return res;
    }
    
    public int[][] merge(int[][] intervals) {
        int n = intervals.length;
        // 特殊情况:只有一个区间或者没有区间
        if (n == 1 || n == 0) {
            return intervals;
        }
        // 数据转换
        List<Interval> intervalList = new ArrayList<Interval>();
        for (int i = 0;i < n;i++) {
            intervalList.add(new Interval(intervals[i][0],intervals[i][1]));
        }
        // 调用处理合并函数
        List<Interval> res = merge(intervalList);
        // 结果数据处理
        int[][] ans = new int[res.size()][2];
        int k = 0;
        for (Interval i :  res) {
            ans[k][0] = i.start;
            ans[k][1] = i.end;
            k++;
        }
        return ans;
    }
}

直接操作原有数组

class Solution {
    public int[][] merge(int[][] intervals) {
        // 调用java 排序API,按照起始位置排序
        Arrays.sort(intervals, (p, q) -> p[0] - q[0]);

        int n = intervals.length;
        int[][] ans = new int[n][2];

        int last = 0;
        for (int[] item : intervals) {
            if(last > 0 && item[0] <= ans[last - 1][1]) {// 可以合并
                if (item[1] > ans[last - 1][1]) {
                    ans[last - 1][1] = item[1];
                }
                //  ans[last - 1][1] = Math.max(ans[last - 1][1], item[1]);

            } else {
                // 新增区间
                ans[last][0] = item[0];
                ans[last][1] = item[1];
                last++;
            }
        }

        // 构造结果
        int[][] ansNew = new int[last][2];
        int i = 0;
        for(int[] item : ans) {
            ansNew[i][0] = item[0];
            ansNew[i][1] = item[1];
            i++;
            if (i == last) {
                break;
            }
        }
        return ansNew;
    }
}

// 使用ArrayList存储新的区间对,然后再转成int[]
public class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (p, q) -> p[0] - q[0]); // 按照左端点从小到大排序
        List<int[]> ans = new ArrayList<>();
        for (int[] p : intervals) {
            int m = ans.size();
            if (m > 0 && p[0] <= ans.get(m - 1)[1]) { // 可以合并
                ans.get(m - 1)[1] = Math.max(ans.get(m - 1)[1], p[1]); // 更新右端点最大值
            } else { // 不相交,无法合并
                ans.add(p); // 新的合并区间
            }
        }
        return ans.toArray(new int[ans.size()][]);
    }
}

57、插入区间

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

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

示例 1:

输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]

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

链接:https://leetcode-cn.com/problems/insert-interval

思路

  • 遍历一边
    • 未插入
      • 找到出入位置
        • 是否真的相交
          • 不是真相交,按照大小依次加入到结果中
          • 真的相交,合并,加入到结果中
          • 加入标记为已插
      • 没有找到插入位置,将源列表中的元素加入到结果中
    • 已插入
      • 将剩余元素依次合并到结果中

代码

class Solution {
    // 区间类
    class Interval{
        public int start;
        public int end;
        public Interval(int s,int e){
            this.start = s;
            this.end = e;
        }
        
        public Interval(Interval i) {
            this.start = i.start;
            this.end = i.end;
        }

        public Interval merge(Interval i) {
            this.start = Math.min(this.start,i.start);
            this.end = Math.max(this.end,i.end);
            return this;
        }
        
    }
    
    public int[][] insert(int[][] intervals, int[] newInterval) {
        int n = intervals.length;     
        LinkedList<Interval> res = new LinkedList<Interval>();// 结果列表
        boolean isMerged = false;// 新节点已插入
        if(n == 0) {
            int[][] res1 = new int[1][2];
            res1[0][0] = newInterval[0];
            res1[0][1] = newInterval[1];
            return res1;
        }
        
        for (int i = 0;i < n;i++) {
            if (isMerged) {// 已合并
                if (res.getLast().end < intervals[i][0]) {// 不相交
                    res.add(new Interval(intervals[i][0],intervals[i][1]));
                }else {// 一定相交
                    // 合并
                    res.getLast().merge(new Interval(intervals[i][0],intervals[i][1]));
                }
            }else {// 未合并
                if (newInterval[0] > intervals[i][1]) {// 不相交
                    res.add(new Interval(intervals[i][0],intervals[i][1]));
                }else {// 可能相交
                    Interval t = new Interval(intervals[i][0],intervals[i][1]);
                    if (newInterval[1] >= intervals[i][0]) {
                        res.add(t.merge(new Interval(newInterval[0],newInterval[1])));
                    } else {
                        // 依次插入两个区间
                        res.add(new Interval(newInterval[0],newInterval[1]));
                        res.add(new Interval(intervals[i][0],intervals[i][1]));
                    }
                    isMerged = true;
                }
            }
        }
        if (!isMerged) {
            res.add(new Interval(newInterval[0],newInterval[1]));
        }
        
        int[][] ans = new int[res.size()][2];
        int k = 0;
        for (Interval i : res) {
            ans[k][0] = i.start;
            ans[k][1] = i.end;
            k++;
        }
        
        return ans;
    }
}

// 1mm 代码
class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        List<int[]> res = new ArrayList<>();
        int cur = 0;
        for(int[] interval : intervals){// 遍历
            if(interval[1] < newInterval[0]){// 不可能相交
                res.add(interval);          // 加入结果
                cur++;
            }else if(newInterval[1] < interval[0]){// 不可能相交
                res.add(interval);
            }else{// 相交,更新结果
                newInterval[0] = Math.min(interval[0],newInterval[0]);
                newInterval[1] = Math.max(interval[1],newInterval[1]);   
            }
        }
        res.add(cur,newInterval);// 将合并的区间插入到结果的第cur位置

        // 数据转换
        int[][] intervalNew = new int[res.size()][2];
        int index = 0;
        for(int[] interval : res){
            intervalNew[index++] = interval;
        }
        return intervalNew;
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:56、57、合并区间

Count:1.7k

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-16, 20:52:46

Url:http://jiafeimao-gjf.github.io/2020/07/26/56%E3%80%8157%E3%80%81%E5%90%88%E5%B9%B6%E5%8C%BA%E9%97%B4/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation