这是一个 O(N lg N)
Java实现,扩展了@Nikita Rybak提供的答案。
我的解决方案找到了至少与另一个间隔重叠的每个间隔,并将它们都视为重叠间隔。例如,两个间隔(1, 3)
与(2, 4)
OP最初提出的问题相互重叠,因此在这种情况下有2个重叠间隔。换句话说,如果间隔A与间隔B重叠,则我将A和B都添加到重叠的结果间隔集中。
现在考虑间隔(1, 100)
,(10, 20)
和(30, 50)
。我的代码将发现:
[ 10, 20] overlaps with [ 1, 100]
[ 30, 50] overlaps with [ 1, 100]
Resulting intervals that overlap with at least one other interval:
[ 1, 100]
[ 30, 50]
[ 10, 20]
为了防止(1, 100)
被计数两次,我使用了Set
仅保留唯一的Interval对象的Java 。
我的解决方案遵循此轮廓。
- 按起点对所有间隔进行排序。这一步是
O(N lg N)
。
- 跟踪
intervalWithLatestEnd
,具有最新终点的时间间隔。
- 遍历排序列表中的所有间隔。如果间隔与重叠
intervalWithLatestEnd
,则将两者都添加到集合中。intervalWithLatestEnd
需要时进行更新。这一步是O(N)
。
- 返回Set(并在需要时转换为List)。
总运行时间为O(N lg N)
。它需要一个输出Set of size O(N)
。
实作
为了将间隔添加到集合中,我equals()
按预期创建了一个覆盖的自定义Interval类。
class Interval {
int start;
int end;
Interval(int s, int e) {
start = s; end = e;
}
@Override
public String toString() {
return String.format("[%3d, %3d]", start, end);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + start;
result = prime * result + end;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Interval other = (Interval) obj;
if (start != other.start)
return false;
if (end != other.end)
return false;
return true;
}
}
这是运行算法的代码:
private static List<Interval> findIntervalsThatOverlap(List<Interval> intervals) {
Set<Interval> set = new HashSet<Interval>();
Collections.sort(intervals, (x, y) -> Integer.compare(x.start, y.start));
Interval intervalWithLatestEnd = null;
for (Interval interval : intervals) {
if (intervalWithLatestEnd != null &&
interval.start < intervalWithLatestEnd.end) {
set.add(interval);
set.add(intervalWithLatestEnd);
System.out.println(interval + " overlaps with " +
intervalWithLatestEnd);
}
if (intervalWithLatestEnd == null ||
intervalWithLatestEnd.end < interval.end) {
intervalWithLatestEnd = interval;
}
}
return new ArrayList<Interval>(set);
}
测试用例
这是一个运行OP原始间隔的测试用例:
public static void testcase() {
List<Interval> intervals = null;
List<Interval> result = null;
intervals = new ArrayList<Interval>();
intervals.add(new Interval(1, 3));
intervals.add(new Interval(12, 14));
intervals.add(new Interval(2, 4));
intervals.add(new Interval(13, 15));
intervals.add(new Interval(5, 10));
result = findIntervalsThatOverlap(intervals);
System.out.println("Intervals that overlap with at least one other interval:");
for (Interval interval : result) {
System.out.println(interval);
}
}
结果:
[ 2, 4] overlaps with [ 1, 3]
[ 13, 15] overlaps with [ 12, 14]
Intervals that overlap with at least one other interval:
[ 2, 4]
[ 1, 3]
[ 13, 15]
[ 12, 14]
最后,这是一个更高级的测试用例:
public static void testcase() {
List<Interval> intervals = null;
List<Interval> result = null;
intervals = new ArrayList<Interval>();
intervals.add(new Interval(1, 4));
intervals.add(new Interval(2, 3));
intervals.add(new Interval(5, 7));
intervals.add(new Interval(10, 20));
intervals.add(new Interval(15, 22));
intervals.add(new Interval(9, 11));
intervals.add(new Interval(8, 25));
intervals.add(new Interval(50, 100));
intervals.add(new Interval(60, 70));
intervals.add(new Interval(80, 90));
result = findIntervalsThatOverlap(intervals);
System.out.println("Intervals that overlap with at least one other interval:");
for (Interval interval : result) {
System.out.println(interval);
}
}
结果:
[ 2, 3] overlaps with [ 1, 4]
[ 9, 11] overlaps with [ 8, 25]
[ 10, 20] overlaps with [ 8, 25]
[ 15, 22] overlaps with [ 8, 25]
[ 60, 70] overlaps with [ 50, 100]
[ 80, 90] overlaps with [ 50, 100]
Intervals that overlap with at least one other interval:
[ 2, 3]
[ 8, 25]
[ 9, 11]
[ 50, 100]
[ 1, 4]
[ 15, 22]
[ 10, 20]
[ 60, 70]
[ 80, 90]