GuilinDev

Lc0056

05 August 2008

56 Merge Intervals

原题概述

Given a collection of intervals, merge all overlapping intervals.

Example 1:

1
2
3
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

Example 2:

1
2
3
Input: [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considerred overlapping.

题意和分析

要求合并区间,可以对区间集进行自定义的排序,按照start的值从小到大排序,排完序后开始合并,首先初始化为第一个区间的start和end,然后从开始遍历,如果遍历到的区间和当前区间无重叠,直接将区间存入到结果中;如果有重叠,将结果中最后一个区间的end值更新为这个end值和遍历到的end值之间的较大值,直至结束。排序的时间是主要的指数, O(n log(n))。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
class Solution {
    public List<Interval> merge(List<Interval> intervals) {
        if (intervals.size() <= 1) {
            return intervals;
        }

        //Java8的函数式编程
        intervals.sort(Comparator.comparingInt(i -> i.start));

        List<Interval> result = new LinkedList<>();//链表保持顺序

        //初始化
        int start = intervals.get(0).start;
        int end = intervals.get(0).end;

        for (Interval interval : intervals) {
            if (interval.start <= end) {//遍历到的interval的start小于之前的end,有重叠,先延伸
                end = Math.max(end, interval.end);
            } else {//没有重叠,将当前的interval加入到结果集
                result.add(new Interval(start, end));
                //加入之前的区间后,把start和end更新为当前遍历到的interval的start和end
                start = interval.start;
                end = interval.end;
            }
        }
        //最后的一个区间没有遍历到的interval比较,需要加入
        result.add(new Interval(start, end));

        return result;
    }
}

题目输入变了,变成了一个二维数组而不是一个class,更新解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
    public int[][] merge(int[][] intervals) {
        if (intervals.length <= 1) {
            return intervals;
        }

        // Ascending order
        Arrays.sort(intervals, Comparator.comparingInt(i0 -> i0[0]));

        List<int[]> result = new ArrayList<>();
        int[] newInterval = intervals[0]; // newInterval用来记录已经合并和待合并的区间
        result.add(newInterval); // 每次都来检查结果集中的最后一个区间

        // 遍历每一个二维数组,比较已经合并的区间的尾和新遍历到的头
        for (int[] interval : intervals) {
            if (interval[0] <= newInterval[1]) { // 当前遍历到的区间的头和已经合并的区间的尾
                newInterval[1] = Math.max(newInterval[1], interval[1]); // 更新已合并的区间的尾
            } else { // 断了
                newInterval = interval;
                result.add(newInterval);
            }
        }
        return result.toArray(new int[result.size()][]);
    }
}

也可以一个PriorityQueue,先把所有intervals放入到pq中(排好序),然后每次从pq和结果数组各取一个interval出来,一个是当前,一个是之前,二者比较头尾,如果合并,就把结果数组中的之前的数组删除,合并二者创建一个新的interval然后放入到结果数组中;如果不合并,就直接把pq中弹出来的interval加入result中,直到pq中不再有区间为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public int[][] merge(int[][] intervals) {
        List<int[]> result = new ArrayList<>();
        if (intervals == null || intervals.length == 0) {
            return intervals;
        }

        PriorityQueue<int[]> queue = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);   // ascending order of start times
        
        for (int[] interval : intervals) { // 所有数据加入pq中
            queue.add(interval);
        }

        result.add(queue.poll()); // 初始数据
        
        while (queue.size() != 0) {
            int[] current = queue.poll();
            int[] prev = result.get(result.size() - 1);

            if (prev[1] >= current[0]) {    // this means merge current and prev interval
                result.remove(result.get(result.size() - 1));
                result.add(new int[]{prev[0], Math.max(prev[1], current[1])});
            } else {
                result.add(new int[]{current[0], current[1]});   // put the current interval as it is
            }
        }
        return result.toArray(new int[result.size()][]);
    }
}