LeetCode: Insert Interval & Merge Interval

1、Insert Interval

Description: Given a set of non-overlapping intervals, the intervals were initially sorted according to their start times, insert a new interval into the intervals (merge if necessary).

Example: Give [1,2],[3,5],[6,7],[8,10],[12,16],insert and merge [4,9] in as [1,2],[3,10],[12,16].

This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].

题意:将一个新的区间插入到一组有序的区间中,并根据需要对区间进行合并。

思路:因为区间是有序的,那么下一个区间的起始值肯定大于上一个区间的结束值,因此可以将区间映射到一个数组中,每个区间的两个值对应数组中的两个相邻的元素,那么构造的数组也一定是有序的。如下所示

构造完数组后,我们可以查找新的区间对应的起始值在数组中位置,并根据位置合并相应的区间。

因此可以构造如下算法:

step 1: 根据区间构造新的数组;

Step 2:在数组中找到第一个比新区间的起始值大的元素),并判断该元素与原区间的关系,分为两种:

1)原区间起始值:例如插入[11, 13],先判断比11大的第一个元素时12,12对应原区间[12,16]的起始值,接下来要找一个大于新区间的结束值的元素,即找到16,那么可以发现[11,13]与区间[12,16]存在覆盖,那么就可以将两者合并为[11,16]。如果两个区间有覆盖(如下图),找到两个区间的最小起始值作为合并后的起始值,两个区间的最大结束值作为合并后区间的结束值。否则,新区间将作为一个单独的区间插入结果集中。


2) 原区间结束值:这样就可以判断新区间的起始值在该元素对应的原区间中,所以不管原区间的结束值在哪,都会存在区间覆盖,而且原区间的起始值会成为合并后的区间的起始值,然后判断新区间结束值得位置,来确定合并后区间的结束值。


程序代码如下:

public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
        List<Interval> result = new ArrayList<Interval>();
		if(intervals.size() == 0) {
			result.add(newInterval);
			return result;
		}
		int size = intervals.size();
		int[] ele = new int[2*size];
		//将区间映射到数组中
		for(int i=0; i<size; i++) {
			ele[2*i] = intervals.get(i).start;
			ele[2*i+1] = intervals.get(i).end;
		}
		int newS = newInterval.start; //合并后区间的起始值
		int newE = newInterval.end;   //合并后区间的结束值
		int i = 0;
		for(; i<ele.length && ele[i]<newInterval.start; i++) {
			if(i % 2 == 1)  
				result.add(intervals.get(i/2)); //原区间直接加到结果集中 
		}
		newS = (i%2==0) ? newInterval.start : ele[i-1];  //有gap时,确定合并后区间起始值
		if(i == ele.length) {
			newE = newInterval.end;
			result.add(new Interval(newS, newE));
			return result;
		}
		while(i<ele.length && ele[i]<=newInterval.end) {
			i++;
		}
		newE = (i%2==0) ? newInterval.end : ele[i];  //存在gap时,确定合并区间的结束值
		result.add(new Interval(newS, newE));   //将合并后的区间加到结果集
		while(i < ele.length) {  //将剩余的区间加到结果集中
			if((i+1) % 2 == 1)
				result.add(intervals.get(i/2));
			i++;
		}
		return result;
    }

2、Merge Interval

Description: Given a collection of intervals, merge all overlapping intervals. Example: Given [1,3],[2,6],[8,10],[15,18],  return [1,6],[8,10],[15,18].

思路:由于题目没有说明原来的结果集有序,因此在实现的时候应该先对原区间根据起始值进行排序。然后,对于遍历每个区间,判断是否存在gap,如果存在gap,进进行合并,否则直接添加到结果集中。

public List<Interval> merge(List<Interval> intervals) {
        if(intervals.size() == 0)
        	return new ArrayList<Interval>();
        List<Interval> result = new ArrayList<Interval>();
        int size = intervals.size();
        //使用匿名类实现对区间的排序
        Comparator<Interval> comparator = new Comparator<Interval>() {
        	public int compare(Interval I1, Interval I2) {
        		return I1.start - I2.start;
        	}
	};
	Collections.sort(intervals, comparator); //对原区间集合排序
        int start = intervals.get(0).start;  //初始化合并区间的起始值
        int end = intervals.get(0).end;     //初始化合并区间的结束值
        for(int i=1; i<size; i++) {  
        	if(end >= intervals.get(i).start) {  //存在gap
        		start = start<intervals.get(i).start ? start : intervals.get(i).start;  //确定合并区间的起始值
        		end = end>intervals.get(i).end ? end : intervals.get(i).end;  //确定合并区间的结束值
        	} else {
        		result.add(new Interval(start, end));  //不存在gap,或者合并区间与后面区间没有gap,添加到结果集
        		start = intervals.get(i).start;  //重新初始化合并区间起始值
        		end = intervals.get(i).end;    //重新初始化合并区间结束值
        	}
        }
        result.add(new Interval(start, end));  //将最后一个区间加入到结果集
        return result;
    }


猜你喜欢

转载自blog.csdn.net/yangfeisc/article/details/45047789
今日推荐