zoukankan      html  css  js  c++  java
  • LeetCode第[56]题(Java):Merge Intervals

    题目:合并区间

    难度:Medium

    题目内容

     

    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]]
    

    Example 2:

    Input: [[1,4],[4,5]]
    Output: [[1,5]]

    我的思路:因为可能是乱序的,不好逐个比较,所以需要排序

    1、将List内的元素进行排序(利用比较器),然后从前往后比较 ;

    2、当前的end和后一个的start,看是否需要合并

    3、如果需要合并则当前的end等于它自己与后一个的end中取大的,然后将后一个remove()掉 

    我的代码

     1 class Solution {
     2     public List<Interval> merge(List<Interval> intervals) {
     3         Collections.sort(intervals, new MyComparator());
     4         
     5         for (int i = 0; i < intervals.size() - 1; i++) {
     6             if (intervals.get(i).end >= intervals.get(i+1).start) {
     7                 intervals.get(i).end = intervals.get(i).end > intervals.get(i+1).end ? intervals.get(i).end : intervals.get(i+1).end;
     8                 intervals.remove(i+1);
     9                 i--;
    10             }    
    11         }
    12         return intervals;
    13     }
    14 }
    15 
    16 class MyComparator implements Comparator<Interval> {  
    17   
    18     public int compare(Interval one, Interval two) {
    19         return one.start - two.start;
    20     }  
    21       
    22 }  

    我的复杂度:O(NlogN)    主要是排序的那里用了nlogn    剩下的只有n

    编程过程中的问题

    1、忘记比较器怎么实现

          方法一:将List中的类实现Comparable<E>接口(本题的E就是Interval),并重写compareTo方法(一个传入对象)  用自己的值和传入对象的值做比较即可。

    【比较规则:自己比传入对象大就返回零,等于就等于0,小于就小于0,所以一般直接   return   自己 - 传入对象】如下:

        public int compareTo(Interval o) {
            return start - o.start;
        }

            但是,本题的Interval是写死的不能在编辑中修改,但是不要急,还有另外一种办法:

      方法二:自己写一个类实现Comparator<E>接口,并重写compare方法(两个传入对象)

    【比较规则:与上面类似  一般直接 return   前面一个对象 - 后面一个对象】如下:

        public int compare(Interval one, Interval two) {
            return one.start - two.start;
        }  

       扩展:那如果要比较两个属性呢,比如先比较名字,再比较年龄————代码如下

        public int compare(Person one, Person two) {  
            int i = one.name.compareTo(two.name); //比较名字字符串  
            if (i == 0) { //如果名字一样,则继续比较年龄  
                return one.age - two.age;  
            } else { //首先比较名字,名字不一样,则返回比较结果  
                return i;  
            }  
        } 

      使用此方法需要在sort()方法中传入作为第二个参数,(所以一般可直接在sort方法里使用匿名类)如下:

            Collections.sort(intervals, new Comparator<Interval>(){
                @Override
                public int compare(Interval interval1, Interval interval2){
                    return interval1.start - interval2.start;
                }
            });

    2、发现需要合并后,是不能直接将end取后一个的end的,因为后一个的end也是有可能比当前的小的,比如【【1,6】,【3,5】】,所以需要判断一下end的大小;

    3、因为是顺序向后循环的,List调用remove方法去掉后一个之后,i 会指向后一个继续进行循环,但是此时应该仍然指向自己,继续判断后一个是否需要合并,所以需要 i - -。

      扩展:如果是从后往前循环的呢?需要 i ++?

        此时删去了下标i - 1,然后 i -- ,i 移到 下标 i -1 , 而此时的下标 i -1 就是remove之前的 下标 i 所以不再需要做操作。

        例如:下标 0,1,2  此时 i 等于2 ,将1remove(此时的下标2自动变为1),然后 i -- ,i还是指向原来的2的位置。

      所以,当在循环中调用List的remove方法的时候,一定要考虑下标的变化,而调整指针 i 的值

    答案代码

     1 class Solution {
     2     private class IntervalComparator implements Comparator<Interval> {
     3         @Override
     4         public int compare(Interval a, Interval b) {
     5             return a.start < b.start ? -1 : a.start == b.start ? 0 : 1;
     6         }
     7     }
     8 
     9     public List<Interval> merge(List<Interval> intervals) {
    10         Collections.sort(intervals, new IntervalComparator());
    11 
    12         LinkedList<Interval> merged = new LinkedList<Interval>();
    13         for (Interval interval : intervals) {
    14             if (merged.isEmpty() || merged.getLast().end < interval.start) {
    15                 merged.add(interval);
    16             }
    17             else {
    18                 merged.getLast().end = Math.max(merged.getLast().end, interval.end);
    19             }
    20         }
    21 
    22         return merged;
    23     }
    24 }

    答案思路:和我的思路是一样的,先排序然后从头到位判断是否需要合并,

    不过他使用了队列,空间复杂度提高了,但是这样避免了remove方法带来的多余的时间复杂度,二者各有好处。

  • 相关阅读:
    ubuntu下文件安装与卸载
    webkit中的JavaScriptCore部分
    ubuntu 显示文件夹中的隐藏文件
    C语言中的fscanf函数
    test
    Use SandCastle to generate help document automatically.
    XElement Getting OuterXML and InnerXML
    XUACompatible meta 用法
    Adobe Dreamweaver CS5.5 中文版 下载 注册码
    The Difference Between jQuery’s .bind(), .live(), and .delegate()
  • 原文地址:https://www.cnblogs.com/Xieyang-blog/p/9034145.html
Copyright © 2011-2022 走看看