leetcode 57. Insert Interval

题目描述:

Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]

Example 2:

Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].

NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.

 

思路一:(开辟新空间后合并)

直观的想法是开辟一个新空间,将newInterval和intervals中的元素放到新数组中。插入的逻辑是newInterval的start和原来Intervals的start进行比较,若比前一个小但是比后一个大,则插入到两者中间,再对这个新的二维数组按照leetcode56 题的方法进行合并。

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
         if(intervals==null||intervals.length==0){
             return new int[][]{newInterval};//返回一个二维数组
         }
    	 int[][] newArr=new int[intervals.length+1][2];
    	 int i;
    	 for(i=0;i<newArr.length;i++){
             //在到达最后一个元素之前还没break,说明旧数组中的interval的start都比新插入的小,所以还没有break
    		//此时直接将新插入的interval放到newArr的最后一位即可
             if(i==newArr.length-1){
                 newArr[i]=newInterval;
    			 break; 
             }
    		 if(intervals[i][0]<newInterval[0]){
    			 newArr[i]=intervals[i];
    		 }else{
    			 newArr[i]=newInterval;
    			 break;
    		 }
    	 }
    	 int j=i+1;
    	 while(j<newArr.length){
    		 newArr[j++]=intervals[i++];
    	 }
    	 return merge(newArr);        
    }
    public int[][] merge(int[][] intervals) {
        int len=intervals.length;
        int num=0;//记录合并完数组的元素个数
        for(int i=1;i<len;i++){
            if(intervals[i][0]<=intervals[num][1]){//第二个区间的start小于第一个区间的end
                if(intervals[i][1]>intervals[num][1]){
                    intervals[num][1]=intervals[i][1];
                }
            }else{//不能合并,将数字加入
                num++;
                intervals[num]=intervals[i];//将当前的interval设置成最新的inerval
            }
        }
        return Arrays.copyOfRange(intervals,0,num+1);// copyOfRange将指定数组的指定范围复制到一个新数组。
    }
}

 

思路二、(一边判断一边合并)

从头开始遍历intervals,在遍历的过程中逐个判断newInterval和intervals的当前元素是否可以合并(有交集就可以合并),合并后更新newIntervals的值(更新为合并后的值),再接着用这个newIntervals和下一个元素判断,是否可以合并。

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        if(intervals==null||intervals.length==0){
             return new int[][]{newInterval};//返回一个二维数组
         }
        ArrayList<int[]> list=new ArrayList<>();
        for(int i=0;i<intervals.length;i++){
        	if(newInterval[0]<intervals[i][0]){
        		int[] tmp=intervals[i];
        		intervals[i]=newInterval;
        		newInterval=tmp;       		
        	}
          
            //判断是否可以合并,若不可,则将当前intervals加入ret,继续和下一个做判断
            //若可以,则进行合并,将合并后的结果和下一个做判断
            if(isInsect(intervals[i], newInterval)){
                //进行合并,并更新interval
                newInterval[0]=Math.min(intervals[i][0],newInterval[0]);
                newInterval[1]=Math.max(intervals[i][1],newInterval[1]);
            }else{
            	 //判断当前需要进行合并的是否是最后一个区间
                if(i==intervals.length-1){
                    list.add(intervals[i]);
                    list.add(newInterval);                   
                }else {
                    list.add(intervals[i]);//将当前intervals加入ret,继续用这个newInterval和下一个区间判断
                }
            }  
        }
        //防止合并后成为最后一个区间的可能性
        if(!list.contains(newInterval)){
            list.add(newInterval);
        }
        int[][] ret=new int[list.size()][2];
        int k=0;
        for(int[] ele:list){
            ret[k++]=ele;
        }
        return ret; 
    }
    private boolean isInsect(int[] o1,int[] o2){
    	if(o2[0]<=o1[1]){//02的start小于o1的end
    		return true;
    	}
		return false;    	
    }
}

思路三、

不排序,直接插入时间间隔,插入的时间间隔的位置分为三部分:

1.插入位置的左侧

2.插入位置(有重叠/无重叠)

3.插入位置的右侧

这三个位置分别做处理,只在插入位置处理可能的情况即可,时间复杂度o(n),空间复杂度o(n)

实现3:参考了这篇博客的思路https://blog.csdn.net/makuiyu/article/details/44265105

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        if(intervals==null||intervals.length==0){
            return new int[][]{newInterval};//返回一个二维数组
        }
        int[][] newArr=new int[intervals.length+1][2];
        int i=0,j=0;
        //先插入比newInterval小的前半截
        while(i<intervals.length&&intervals[i][1]<newInterval[0]){
            newArr[j++]=intervals[i++];
        }
        //再插入newInterval
        newArr[j]=newInterval;
        while(i<intervals.length&&newArr[j][1]>=intervals[i][0]){
            newArr[j][0]=Math.min(intervals[i][0],newInterval[0]);
            newArr[j][1]=Math.max(intervals[i][1],newInterval[1]);
            i++;
        }
        while (i<intervals.length){
            newArr[++j]=intervals[i++];
        }
        return Arrays.copyOfRange(newArr,0,j+1);
    }
}

 实现4:推荐使用方法

和实现2的思路是一样的,就是一边遍历intervals,一边进行合并;

因为我们在判断两个interval是否有交集时,必须先对这两个interval按照start进行排序,再将排序后后一个interval的start和前一个interval的end进行比较来判断。

进行此时再合并的过程中会遇到两种情况,

1. intervals[i]的start比newInterval的start小,此时intervals[i]排在前面

此时如果intervals[i]的end比newInterval的start小,则两者必定没有交集,此时我们将intervals[i]加入结果集。

2.intervals[i]的start比newInterval的start大,此时newInterval需要排在前面

此时如果newInterval的intervals的start小,则两者必定没有交集,此时我们将intervals[i]加入结果集。

如果不是这两种没有交集的情况,则intervals[i]和newIntervalyi一定有交集,此时我们通过求交集的方法更新newInterval.

然后接着用这个newInterval和intervals[i]进行判断。

求交集:起点取两个interval start的较小者

              终点取两个interval end的较大者

public int[][] insert3(int[][] intervals, int[] newInterval) {
	if (intervals == null || newInterval == null) {
		return intervals;
	}
	List<int[]> res = new ArrayList<>();
	int p = 0;//记录上一次插入左边interval的位置
	for (int[] item : intervals) {
		//item的start比newInterval的start小,此时通过判断item的end和newInterval的start来确定是否有交集。没有交集,则将当前item加入结果集
		if (item[1] < newInterval[0]) {
			res.add(item);
			++p;
		} else if (newInterval[1]<item[0]) {
			//item的start比newInterval的start大,此时通过判断item的start和newInterval的end来确定是否有交集
			res.add(item);
		} else {//有交集,则获取交集
			newInterval[0] = Math.min(item[0], newInterval[0]);
			newInterval[1] = Math.max(item[1], newInterval[1]);
		}
	}
	res.add(p, newInterval);
	int[][] ans = new int[res.size()][2];
	for (int i = 0; i < res.size(); ++i) {
		ans[i] = res.get(i);
	}
	return ans;      
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值