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方法带来的多余的时间复杂度,二者各有好处。

  • 相关阅读:
    redis requires Ruby version >= 2.2.2.
    redis-持久化、主从复制、集群
    lucene索引文件大小优化小结
    spring+websocket的整合实例--可使用
    使用nexus3.10搭建maven私有仓库
    oracle 查看所有表的数据量并排序
    Spring框架-经典的案例和demo,一些可以直接用于生产,使用atomikos来处理多数据源的一致性事务等
    ORACLE WITH AS 用法
    判断对象部分属性是否为空
    代码行数统计
  • 原文地址:https://www.cnblogs.com/Xieyang-blog/p/9034145.html
Copyright © 2011-2022 走看看