题目链接

LeetCode

题目描述

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

提示:

  • 1 <= intervals.length <= 104
  • intervals[i].length == 2
  • 0 <= starti <= endi <= 104

    解题思路

    排序

    如果我们按照区间的左端点排序,那么在排完序的列表中,可以合并的区间一定是连续的。如下图所示,标记为蓝色、黄色和绿色的区间分别可以合并成一个大区间,它们在排完序的列表中是连续的:
    56. 合并区间 - 图1
    我们用数组 res 存储最终的答案。

首先,我们将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 res 数组中,并按顺序依次考虑之后的每个区间:

  1. 如果当前区间的左端点在数组 res 中最后一个区间的右端点之后,那么它们不会重合,我们可以直接将这个区间加入数组 res 的末尾;
  2. 否则,它们重合,我们需要用当前区间的右端点更新数组 res 中最后一个区间的右端点,将其置为二者的较大值。
  1. class Solution {
  2. public:
  3. vector<vector<int>> merge(vector<vector<int>>& intervals) {
  4. int len = intervals.size();
  5. if(len<2)
  6. return intervals;
  7. sort(intervals.begin(),intervals.end());
  8. vector<vector<int>> res;
  9. for(int i=0;i<len;++i){
  10. int L = intervals[i][0],R = intervals[i][1];
  11. if(!res.size()||res.back()[1]<L){
  12. res.push_back({L,R});
  13. }else{
  14. res.back()[1] = max(res.back()[1],R);
  15. }
  16. }
  17. return res;
  18. }
  19. };
  20. class Solution {
  21. public:
  22. vector<vector<int>> merge(vector<vector<int>>& intervals) {
  23. int len = intervals.size();
  24. if(len<=1){
  25. return intervals;
  26. }
  27. vector<vector<int>> ans;
  28. sort(intervals.begin(),intervals.end(),[](vector<int>&a,vector<int>&b){
  29. return a[0]<b[0];
  30. });
  31. int l = intervals[0][0],r = intervals[0][1];
  32. for(int i=1;i<len;i++){
  33. // 如果没有重合
  34. if(intervals[i][0]>r){
  35. ans.push_back({l,r});
  36. l = intervals[i][0];
  37. r = intervals[i][1]; // 如果有重合并且r大于之前
  38. }else if(intervals[i][1]>r){
  39. r = intervals[i][1];
  40. }
  41. }
  42. // 将最后一个加入结果
  43. ans.push_back({l,r});
  44. return ans;
  45. }
  46. };
// List版
class Solution {
    public int[][] merge(int[][] intervals) {
        if(intervals.length < 2){
            return intervals;
        }
        Arrays.sort(intervals, new Comparator<int[]>() {
            public int compare(int[] a, int[] b){
                return a[0] - b[0];
            }
        });
        // lambda表达式
        // Arrays.sort(intervals, (a1, a2) -> a1[0] - a2[0]);
        List<int[]> res = new LinkedList<int[]>();
        for(int i = 0; i < intervals.length; ++i){
            int L = intervals[i][0], R = intervals[i][1];
            if(res.size() == 0 || res.get(res.size() - 1)[1] < L){
                res.add(new int[]{L, R});
            }else{
                res.get(res.size() - 1)[1] = Math.max(res.get(res.size() - 1)[1], R);
            }
        } 
        return res.toArray(new int[res.size()][]); 
    }
}
// 数组版
class Solution {
    public int[][] merge(int[][] intervals) {
        if(intervals.length < 2){
            return intervals;
        }
        // 排序,先按左边界从小到大排, 再按右边界从小到大排
        Arrays.sort(intervals, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
        // pos标记当前合并后的位置,即合并到第几个区间
        int pos = 0;
        // i标记当前合并的位置,即遍历到第几个区间
        for(int i = 1; i < intervals.length; ++i){
            // 如果当前遍历到的区间左边界在前面区间中,进行合并
            if(intervals[i][0] <= intervals[pos][1]){
                intervals[pos][1] = Math.max(intervals[pos][1], intervals[i][1]);                
            }else{
                // 开始新的区间合并
                ++pos;
                intervals[pos][0] = intervals[i][0];
                intervals[pos][1] = intervals[i][1];
            }
        }
        // 将数据返回
        int[][] res = new int[pos + 1][2];
        for(int i = 0; i <= pos; ++i){
            res[i][0] = intervals[i][0];
            res[i][1] = intervals[i][1];
        }
        return res;
    }
}
  • 时间复杂度 O(nlogn)
  • 空间复杂度 O(logn)