Merge Intervals

Given a collection of intervals, merge all overlapping intervals.

For example,
Given [1,3],[2,6],[8,10],[15,18],
return [1,6],[8,10],[15,18].

解法一:从头开始进行两两合并

/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
class Interval implements Comparable<Interval>
{
	int start;
	int end;
	Interval() { start = 0; end = 0; }
	Interval(int s, int e) { start = s; end = e; }
	public int compareTo(Interval o)
	{
		return this.start - o.start;
	}
}
public class Solution {
    public static List<Interval> merge(List<Interval> intervals)
	{
		Collections.sort(intervals);
		List<Interval> result = new ArrayList<Interval>();
        int length = intervals.size();
        if(length <= 1)
        	return intervals;
        Interval first = intervals.get(0),second = new Interval();
        for(int i = 1; i < length; i++)
        {
        	second = intervals.get(i);
        	if(second.start > first.end)
        	{
        		result.add(first);
        		first = second;
        	}
        	else 
        	{
        		first.end = Math.max(first.end, second.end);
			}
        }
        //最后一次合并
        result.add(first);
        return result;
    }
}

解法二:

区间合并 和 求最长区间 一样,关键在于如何记录区间信息,能够降低复杂度。


最简单的思路是用一个bool数组,记录区间中的每一位是否被覆盖。

例如:

intervals: [1, 4] [8, 9] [20, 30] [7, 14] [2, 9]

设一个数组 bool f[30],初始化全部为false

[1, 4]就把f[1]..f[4]全部置为true

其他区间一次类推,最后扫描f数组,就能得到区间合并的结果。

这种做法对于小数据还行,大数据会超市。


这样做,存在很多重复工作,例如[1, 4] [8, 9] [7, 14] [2, 9]这四个区间,会反复将f[2] f[3] f[4][ f[5] f[6] f[7] f[8] f[9]设为true。

所以,我们需要考虑的是如何去除重复的工作。实际上,两个端点就能描述出一个区间,关键在于如何标记出两个端点,让我们在扫描时能够知道这个区间被覆盖。


一个很巧妙的做法就是进入一个区间就加1,出一个区间就减1,如果数值大于0,说明当前处于一个区间中。

还是以刚刚的intervals为例。

设数组 int l[30], r[30],初始化全部为0 

[1, 4]:l[1]++, r[4]--

[8, 9]:l[8]++, r[9]--

...

扫描时,用一个count记录,每次:

count += l[i],如果count>0说明i处于一个区间中

count -= r[i],如果count==0说明i是一个区间的尾端点

public static List<Interval> merge(List<Interval> intervals) 
	{
        List<Interval> result = new ArrayList<Interval>();
        int length = intervals.size();
        if(length <= 1)
        	return intervals;
        int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE;
        for(int i = 0;i < length; i++)
        {
        	Interval tmp = intervals.get(i);
        	max = Math.max(max, tmp.end);
        	min = Math.min(min, tmp.start);
        }
        int[] left = new int[max + 1];
        int[] right = new int[max + 1];
        for(int i = 0;i < length; i++)
        {
        	Interval tmp = intervals.get(i);
        	left[tmp.start]++;
        	right[tmp.end]--;
        }
        int start = -1, count = 0;
        for(int i = min; i <= max; i++)
        {
        	count += left[i];
        	if(count > 0 && start == -1)
        		start = i;
        	count += right[i];
        	if(count == 0 && start != -1)
        	{
        		result.add(new Interval(start, i));
        		start = -1;
        	}
        }
        return result;
    }



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值