zoukankan      html  css  js  c++  java
  • Leetcode之插入区间

    问题描述:

    给出一个无重叠的 ,按照区间起始端点排序的区间列表。
    在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

    示例 1:

    输入:intervals = [[1,3],[6,9]], newInterval = [2,5]
    输出:[[1,5],[6,9]]

    示例 2:

    输入:intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
    输出:[[1,2],[3,10],[12,16]]
    解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。

    问题解法:

    法一:排序+合并

    因为在之前已经写过合并区间的方法了。所以可以得到一个新区间再排序。

    class Solution {
        public  int[][] merge(int[][] intervals) {
        	if(intervals==null)
        		return null;
        	boolean[] flags=new boolean[intervals.length];
        	int num=0;
        	for(int i=0;i<intervals.length;i++) {
        		//排序
        		for(int j=i+1;j<intervals.length;j++) {
        			if(intervals[j][0]<intervals[i][0]) {
        				//交换
        				int temp1=intervals[j][0];
        				int temp2=intervals[j][1];
        				intervals[j][0]=intervals[i][0];
        				intervals[j][1]=intervals[i][1];
        				intervals[i][0]=temp1;
        				intervals[i][1]=temp2;
        			}
        		}
        		if(i!=0) {
        			if(intervals[i][0]<=intervals[i-1][1]) {
        				intervals[i][0]=intervals[i-1][0];//合并成一个区间
        				intervals[i][1]=Math.max(intervals[i-1][1], intervals[i][1]);
        				flags[i-1]=false;
        				num--;
        			}
        		}
        		flags[i]=true;
        		num++;
        	}
        	int[][] re=new int[num][2];
        	for(int i=0,j=0;i<flags.length;i++) {
        		if(flags[i])
        			re[j++]=intervals[i];
        	}
        	return re;
        }
        public  int[][] insert(int[][] intervals, int[] newInterval) {
        	int[][] re=new int[intervals.length+1][2];
        	for(int i=0;i<intervals.length;i++) {
        		re[i][0]=intervals[i][0];
        		re[i][1]=intervals[i][1];
        	}
        	re[re.length-1][0]=newInterval[0];
        	re[re.length-1][1]=newInterval[1];
        	return merge(re);
        }
    }
    

    法二:二分查找+合并

    上面的排序方法我们选择的是冒泡排序(合并区间题目的算法)。这道题目给的是有序的区间集合。因此我们可以对区间集合进行二分查找。将排序问题变为二分查找。再进行合并。

    class Solution {
    public  int[][] getRe(int[][]intervals, int[] newInterval){
        if(intervals==null||intervals.length==0)
        		{
    			int[][] re=new int[1][2];
    			re[0][0]=newInterval[0];
    			re[0][1]=newInterval[1];
    			return re;
        		}
    		int[][] re=new int[intervals.length+1][2];
    		int start=0,end=intervals.length;
                    //注意这里end是len不是len-1
    		int mid=(start+end)/2;
    		while(start<end) {
    			 mid=(start+end)/2;
    			if(newInterval[0]>intervals[mid][0]) {
    				if(start!=mid)
    					start=mid;
    				else 
    					break;
    			}else if(newInterval[0]==intervals[mid][0]) {
    				break;
    			}else {
    				if(end!=mid)
    				end=mid;
    				else
    					break;
    			}
    		}
    		for(int i=0;i<intervals.length;i++) {
    			if(i<mid)
    				{
    				re[i][0]=intervals[i][0];
    				re[i][1]=intervals[i][1];
    				}
    			else if(i==mid) {
    				if(start==end&&newInterval[0]<intervals[i][0]) {
    					re[i][0]=newInterval[0];
    					re[i][1]=newInterval[1];
    					re[i+1][0]=intervals[i][0];
    					re[i+1][1]=intervals[i][1];
    				}else {
    					re[i][0]=intervals[i][0];
    					re[i][1]=intervals[i][1];
    					re[i+1][0]=newInterval[0];
    					re[i+1][1]=newInterval[1];
    				}
    			}else {
    				re[i+1][0]=intervals[i][0];
    				re[i+1][1]=intervals[i][1];
    			}
    				
    		}
    		return re;
    	}
        public  int[][] merge(int[][] intervals) {
        	if(intervals==null)
        		return null;
        	boolean[] flags=new boolean[intervals.length];
        	int num=0;
        	for(int i=0;i<intervals.length;i++) {
        		if(i!=0) {
        			if(intervals[i][0]<=intervals[i-1][1]) {
        				intervals[i][0]=intervals[i-1][0];//合并成一个区间
        				intervals[i][1]=Math.max(intervals[i-1][1], intervals[i][1]);
        				flags[i-1]=false;
        				num--;
        			}
        		}
        		flags[i]=true;
        		num++;
        	}
        	int[][] re=new int[num][2];
        	for(int i=0,j=0;i<flags.length;i++) {
        		if(flags[i])
        			re[j++]=intervals[i];
        	}
        	return re;
        }
        public  int[][] insert(int[][] intervals, int[] newInterval) {
        	int[][] re=getRe(intervals,newInterval);
        	return merge(re);
        }
    }
    

    法三:贪心

    贪心算法。我们将整个区间集合分为三部分————在newInterval[0]之前的区间需要全加进去。然后是newInterval区间与最后一个区间合并(如果需要的话)。再将之后的每一个区间添加进来,需要合并的进行合并。

    class Solution {
    public  int[][] insert(int[][] intervals, int[] newInterval) {
        if(intervals==null||intervals.length==0) {
        		int[][] re=new int[1][2];
        		re[0][0]=newInterval[0];
        		re[0][1]=newInterval[1];
        		return re;
        	}
        	ArrayList<int[]>lists=new ArrayList<int[]>();
        	int flag=-1;
        	for(int i=0;i<intervals.length;i++) {
        		if(intervals[i][0]<newInterval[0]) {
        			if(intervals[i][1]<newInterval[0])
        			{//添加i
    	    			int[]b=new int[2];
    					b[0]=intervals[i][0];
    					b[1]=intervals[i][1];
    					flag=i+1;
    	    			lists.add(b);
        			}
        			else {
        				int[]b=new int[2];
        				b[0]=intervals[i][0];
        				b[1]=Math.max(intervals[i][1], newInterval[1]);
        				lists.add(b);
        				flag=i+1;
    					break;
        			}
        		}else {
        			flag=i;
        			break;
        		}
        	}
        	///添加newInterval
        	if(lists.size()==0) {
        		int[]b=new int[2];
        		b[0]=newInterval[0];
        		b[1]=newInterval[1];
        		lists.add(b);
        	}else {
    	    	int[] t=lists.get(lists.size()-1);
    	    	if(t[1]<newInterval[0]) {//不用合并
    	    		int[]b=new int[2];
    				b[0]=newInterval[0];
    				b[1]=newInterval[1];
    				lists.add(b);
    	    	}else {
    	    		t[1]=Math.max(intervals[flag-1][1], newInterval[1]);
    	    	}
        	}
        	for(int i=flag;i<intervals.length;i++) {
        		int[] a=lists.get(lists.size()-1);
        		if(a[1]>=intervals[i][0]) {
        			if(a[1]<=intervals[i][1])
        			{
        				a[1]=intervals[i][1];
        				for(int j=i+1;j<intervals.length;j++) {
        					int[]b=new int[2];
        					b[0]=intervals[j][0];
        					b[1]=intervals[j][1];
        					lists.add(b);
        				}
        				break;
        			}
        		}else {
        			int[]b=new int[2];
    				b[0]=intervals[i][0];
    				b[1]=intervals[i][1];
        			lists.add(b);
        		}
        	}
        	return (int[][]) lists.toArray(new int[lists.size()][2]);
        }
    }
    

    总结知识点

    • 二分法的端点
    • 贪心算法
    • arraylist转为二维数组的写法((int[][])lists.toArray(new int[lists.size()][2])): toArray()调用的时候一般要传一个数组指定类型,如果不传参数会默认返回Object数组,然后toArray内部会自动判断传入数组大小是否小于list中元素的个数,如果小于则会产生一个大小等于元素个数的新数组,写入数据后返回,否则写入传入的数组,然后返回。
  • 相关阅读:
    Spring声明式事务可能出现的问题
    SpringBoot自定义starter
    查找和最小的K对数字
    SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器
    Redis的数据结构及应用场景
    高考还没结束,这份试卷已经流出,你能拿多少分?
    Linux C/C++编程之(十六)进程及进程控制
    Dom4j修改xml文档引入
    淘宝,京东,苏宁易购技术架构(路线)分析和比较
    android 解析服务器数据使用json还是xml方式
  • 原文地址:https://www.cnblogs.com/code-fun/p/13777522.html
Copyright © 2011-2022 走看看