算法----MergeIntervals

Given a collection of intervals, merge all overlapping intervals.

Example 1:

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:

Input: [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.

给定一系列区间,将重叠的区间合并后返回。

利用优先级队列,按照区间的左端点进行排序,依次不断取出优先级队列中的前两个元素,此时该两个元素是所有区间中左端点最小的两个,然后比较两个区间的重叠情况:

1.没有重叠,此时第一个区间可以从优先级队列中取出,放入到结果集中,第二个区间重新加入到队列中;

2.第一个区间与第二个区间部分重合,此时以第一个左端点,第二个右端点构建一个新区间加入到队列中;

3.第一个区间完全包含第二个区间,则将第一个区间加入到队列中;

重复以上过程,直到队列中只有一个区间,则直接加入到结果集中即可。

代码如下:

public class MergeIntervals {

    class Interval implements Comparable<Interval>{
        public int left;
        public int right;

        public Interval(int left, int right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public String toString() {
            return "Interval{" + "left=" + left + ", right=" + right + '}';
        }

        @Override
        public int compareTo(Interval o) {
            return this.left - o.left;
        }
    }

    public static void main(String[] args) {
        //int[][] input = new int[][]{{1,3},{8,10},{2,6},{15,18}};
        int[][] input = new int[][]{{1,4},{4,5}};
        new MergeIntervals().merge(input);
    }

    public int[][] merge(int[][] input) {

        //利用优先级队列将所有区间按照左端点排序
        PriorityQueue<Interval> pq = new PriorityQueue<>();

        for(int i=0; i<input.length; i++){
            pq.add(new Interval(input[i][0], input[i][1]));
        }

        List<Interval> il = new ArrayList<>();

        //合并区间
        while(pq.size() > 0){
            //如果只有一个区间则不需要合并直接返回
            if(pq.size() == 1) {
                il.add(pq.poll());
            }
            else {
                //取出前两个区间,分情况讨论
                Interval first = pq.poll();
                Interval second = pq.poll();
                //如果第一个区间与第二个没有重合,则第一个区间可以直接加入到结果中,第二个重新队列中
                if(first.right < second.left) {
                    il.add(first);
                    pq.add(second);
                }
                //如果第一个区间右端点在第二个区间之内,则构造一个新区间[first.left, second.right]加入到队列中
                else if(first.right >= second.left && first.right <= second.right) {
                    pq.add(new Interval(first.left, second.right));
                }
                //如果第二个区间在第一个之内,则合并后的新区间为first,加入到队列中
                else if(first.right >= second.right) {
                    pq.add(first);
                }
            }
        }

        int[][] out = new int[il.size()][2];
        for(int i=0; i<il.size(); i++){
            System.out.println(il.get(i));
            out[i] = new int[]{il.get(i).left, il.get(i).right};
        }

        return out;
    }
}

研究一下官方解法

Intuition

If we sort the intervals by their start value, then each set of intervals that can be merged will appear as a contiguous "run" in the sorted list.

Algorithm

First, we sort the list as described. Then, we insert the first interval into our merged list and continue considering each interval in turn as follows: If the current interval begins after the previous interval ends, then they do not overlap and we can append the current interval to merged. Otherwise, they do overlap, and we merge them by updating the end of the previous interval if it is less than the end of the current interval.

A simple proof by contradiction shows that this algorithm always produces the correct answer. First, suppose that the algorithm at some point fails to merge two intervals that should be merged. This would imply that there exists some triple of indices ii, jj, and kk in a list of intervals intsints such that i < j < k and (ints[i], ints[k]) can be merged, but neither (ints[i], ints[j]) nor (ints[j], ints[k]) can be merged. From this scenario follow several inequalities:

Therefore, all mergeable intervals must occur in a contiguous run of the sorted list.

Sorting Example

Consider the example above, where the intervals are sorted, and then all mergeable intervals form contiguous blocks.

将输入区间集合排序,遍历排序集合中每一个区间:

维持一个结果集,如果结果集为空,或者结果集中最后一个区间右端点小于遍历区间左端点,则说明将遍历区间加入到结果集不会产生合并,因此可以直接加入;

如果结果集中最后一个区间右端点不小于遍历区间左端点,则说明将遍历区间加入到结果中,会产生区间合并,合并的结果是结果集中最后区间右端点为遍历区间右端点和结果集最后区间右端点最大值。

private class IntervalComparator implements Comparator<Interval> {
        @Override
        public int compare(Interval a, Interval b) {
            return a.left < b.left ? -1 : a.left == b.left ? 0 : 1;
        }
    }

    public List<Interval> merge(List<Interval> intervals) {
        Collections.sort(intervals, (a, b) -> Integer.compare(a.left, b.left));
        //Collections.sort(intervals, new IntervalComparator());

        LinkedList<Interval> merged = new LinkedList<Interval>();
        for (Interval interval : intervals) {
            // if the list of merged intervals is empty or if the current
            // interval does not overlap with the previous, simply append it.
            if (merged.isEmpty() || merged.getLast().right < interval.left) {
                merged.add(interval);
            }
            // otherwise, there is overlap, so we merge the current and previous
            // intervals.
            else {
                merged.getLast().right = Math.max(merged.getLast().right, interval.right);
            }
        }

        return merged;
    }

Complexity Analysis

  • Time complexity : O(nlogn)

    Other than the sort invocation, we do a simple linear scan of the list, so the runtime is dominated by the O(nlgn)O(nlgn) complexity of sorting.

  • Space complexity : O(1) (or O(n))

    If we can sort intervals in place, we do not need more than constant additional space. Otherwise, we must allocate linear space to store a copy of intervals and sort that.

https://leetcode.com/problems/merge-intervals/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值