可能重复:
Union of intervals
how to overlap intervals efficiently
给定一个间隔列表表示所有整数,如果它们相交或重叠,应该可以将它们折叠成一个间隔,否则给定的间隔不受影响。 比如,如果输入是例如I [(2-6),(1-4),(8-12)],则预期输出为[(1-6),(8-12)] 例如II [(4-7),(2-6),(1-4),(8-12),(7-9)]预期输出为[(1-12)]。
更正:错过了排序部分,所以是的,它是O(nlogn)时间而不是O(n)。感谢您指出了这一点。 我已经编写并测试了O(nlogn)时间和O(2n)空间算法方法。在下面分享这种方法的代码。我有兴趣听取解决这个问题的不同方法,可能更有效率。
//假设每个区间,(2-6)等表示为“区间”对象(下面显示的类定义),其中low = 2且high = 6 //步骤1:按给定间隔的低端点排序 // Step2:找到已排序区间的联合
//输入:
List<Interval> intervalList = new ArrayList<Interval>();
//输出:
List<Interval> unionList = new ArrayList<Interval>();
private static final Comparator<Interval> Low_EPSorter = new LowEPSorter();
class Interval {
int low, high;
Interval(int l, int h, int m) {
low = l;
high = h;
}
}
//// ------- BEGIN:找到给定间隔的联盟的方法---- //////
void UnionOfIntervals() {
//Find intersection and combine intervals as necessary
int sz = intervalList.size();
// sort by low endpoint
Collections.sort(intervalList, Low_EPSorter);
for(int i = 0; i < sz; i++) {
int j = i;
if(j > 0) {
if( Intervals.intersect(intervalList.get(j), intervalList.get(j-1)) ) {
Interval v = union(intervalList.get(j), intervalList.get(j-1));
checkAndAdd(v, unionList);
}
else {
if(i == 1) {
unionList.add(intervalList.get(j-1));
unionList.add(intervalList.get(j));
}
else {
unionList.add(intervalList.get(j));
}
} //No intersection
} //If 2 elements atleast
}
//Print intervals after union
System.out.println("Input intervals after sorting:");
for(Interval v : intervalList) {
System.out.print(v.low + "," + v.high + " ");
}
System.out.println();
System.out.println("Union of intervals:");
for(Interval v : unionList) {
System.out.print(v.low + "," + v.high + " ");
}
}
void checkAndAdd(Interval x, List t) {
int top = t.size()-1;
if( top >=0 && Intervals.intersect(unionList.get(top), x) ) {
Interval v = union(unionList.get(top), x);
t.remove(top);
t.add(v);
}
else {
t.add(x);
}
}
//// ------- END:查找给定间隔的联合的方法---- //////
//// ---帮助方法--- ////
static boolean intersect(Interval a, Interval b) {
boolean r = false;
if(b.high < a.low || b.low > a.high)
r = false;
else if(a.low <= b.high && b.low <= a.high)
r = true;
return r;
}
Interval union(Interval a, Interval b) {
int l = (a.low < b.low) ? a.low : b.low;
int max = (a.high > b.high) ? a.high : b.high;
return new Interval(l, max);
}
private static class LowEPSorter implements Comparator<Interval> {
public int compare(Interval a, Interval b) {
int r = 0;
if(a.low < b.low)
r = -1;
else if(a.low > b.low)
r = 1;
return r;
}
}
答案 0 :(得分:1)
取一个大小为n的数组(其中n是最大数字),并分别用1和-1填充间隔的开始和结束。
我的意思是,如果间隔是
{[1-4],[6-8]}
然后数组元素就像
array[1]=1,array[4]=-1,array[6]=1,array[8]=-1
其余数组的所有其他位置都将设置为零。
现在遍历数组并通过扫描数组我们可以获得间隔,就像
一样{[1-4],[2-5],[7-9]},
首先如上所述填充数组,数组A看起来像(假设起始索引为1):
A=[1,1,0,-1,-1,0,1,0,1]
现在从头开始遍历数组A,取一个变量sum = 0,并将存储在数组位置的值加到sum。
说明数组的每个索引的总和:
在位置1:sum = 1(索引1处为1)
在位置2:sum = 2(索引2处为1)
在位置3:sum = 2(索引3处为0)
在位置4:sum = 1(索引4处为-1)
在位置5:sum = 0(索引5处为-1)
现在总和达到零,这意味着一个间隔在这里结束,所以新的间隔将是[1-5]
在位置6:sum = 0(索引6处为0)
在位置7:sum = 1(索引7处为1)
(在位置7,总和再次变为大于零,这意味着间隔刚刚开始)
在位置8:sum = 1(索引8处为0)
在位置9:sum = 0(索引9处为-1)
间隔从刚刚结束的位置7开始,因此新的间隔范围将是
{[1-5],[7-9]}
希望它有所帮助。
答案 1 :(得分:0)
如果您正在为此问题寻找比O(n)更高效的算法,我不相信您会找到它。无论您使用什么数据结构存储初始间隔值,最糟糕的情况是没有任何间隔重叠,您必须检查每个间隔以确认这一点,因此O(n)。即使使用HashMap
和非常精细的密钥结构,您仍然可以查看O(n)。
有了这个说法,我不确定是否有任何其他方法值得研究,因为你已经找到了一个在最佳时间内解决它的算法,O(n)。
答案 2 :(得分:0)
只是一个想法:管理一组不相交的间隔。从空集开始,添加传入间隔。如果新间隔与一个或两个现有间隔相交,请将它们组合。要计算交叉点,请使用2个TreeMaps引用同一组间隔,但使用不同的键:低限和高限。
答案 3 :(得分:0)
另一个想法: