Hier ist eine O(N lg N)
Implementierung in Java, die die Antwort von @Nikita Rybak erweitert.
Meine Lösung findet jedes Intervall, das sich mit mindestens einem anderen Intervall überschneidet, und zählt beide als überlappende Intervalle. Zum Beispiel überlappen sich die beiden Intervalle (1, 3)
und (2, 4)
die ursprüngliche Frage von OP. In diesem Fall gibt es also zwei überlappende Intervalle. Mit anderen Worten, wenn sich Intervall A mit Intervall B überschneidet, füge ich sowohl A als auch B zu der resultierenden Menge von Intervallen hinzu, die sich überlappen.
Betrachten wir nun die Intervalle (1, 100)
, (10, 20)
und (30, 50)
. Mein Code wird Folgendes finden:
[ 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]
Um zu verhindern, (1, 100)
dass zweimal gezählt wird, verwende ich ein Java Set
, das nur eindeutige Intervallobjekte enthält.
Meine Lösung folgt dieser Gliederung.
- Sortieren Sie alle Intervalle nach Startpunkt. Dieser Schritt ist
O(N lg N)
.
- Behalten Sie
intervalWithLatestEnd
das Intervall mit dem letzten Endpunkt im Auge.
- Durchlaufen Sie alle Intervalle in der sortierten Liste. Wenn sich ein Intervall mit überschneidet
intervalWithLatestEnd
, fügen Sie beide zu einem Satz hinzu. Aktualisieren Sie, intervalWithLatestEnd
wenn nötig. Dieser Schritt ist O(N)
.
- Geben Sie das Set zurück (und konvertieren Sie es bei Bedarf in eine Liste).
Die Gesamtlaufzeit beträgt O(N lg N)
. Es erfordert einen Ausgabesatz von Größe O(N)
.
Implementierung
Um einem Satz Intervalle hinzuzufügen, habe ich eine benutzerdefinierte Intervallklasse erstellt equals()
, die erwartungsgemäß überschrieben wird.
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;
}
}
Und hier ist der Code, der den Algorithmus ausführt:
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);
}
Testfälle
Hier ist ein Testfall, in dem die ursprünglichen Intervalle des OP ausgeführt werden:
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);
}
}
mit dem Ergebnis:
[ 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]
Zum Schluss noch ein fortgeschrittener Testfall:
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);
}
}
mit dem Ergebnis:
[ 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]