Was ist bei zwei inklusive ganzzahligen Bereichen [x1: x2] und [y1: y2], wobei x1 ≤ x2 und y1 ≤ y2, der effizienteste Weg, um zu testen, ob es eine Überlappung der beiden Bereiche gibt?
Eine einfache Implementierung lautet wie folgt:
bool testOverlap(int x1, int x2, int y1, int y2) {
return (x1 >= y1 && x1 <= y2) ||
(x2 >= y1 && x2 <= y2) ||
(y1 >= x1 && y1 <= x2) ||
(y2 >= x1 && y2 <= x2);
}
Ich gehe jedoch davon aus, dass es effizientere Möglichkeiten gibt, dies zu berechnen.
Welche Methode wäre im Hinblick auf die wenigsten Operationen am effizientesten?
performance
comparison
integer
range
WilliamKF
quelle
quelle
Antworten:
Was bedeutet es, wenn sich die Bereiche überschneiden? Dies bedeutet, dass es eine Zahl C gibt, die in beiden Bereichen liegt, d. H.
und
Wenn wir nun annehmen dürfen, dass die Bereiche gut geformt sind (so dass x1 <= x2 und y1 <= y2), reicht es aus, zu testen
quelle
x1 <= y2 && y1 >= x2
, nein?Bei zwei Bereichen [x1, x2], [y1, y2]
quelle
min(x2,y2) - max(x1,y1)
das Ausmaß der Überlappung angegeben ist, falls Sie dies benötigen.Dies kann ein normales menschliches Gehirn leicht verzerren, daher habe ich einen visuellen Ansatz gefunden, der leichter zu verstehen ist:
le Erklärung
Wenn zwei Bereiche "zu fett" sind , um in einen Schlitz zu passen, der genau die Summe der Breite beider ist, überlappen sie sich.
Für Bereiche
[a1, a2]
und[b1, b2]
dies wäre:quelle
a2 - a1 + b2 - b1
überlaufen kann. Um dies zu beheben, ordnen Sie die Formel neu anmax(a2, b2) - a2 - b2 < min(a1, b1) - a1 - b1
, was sich vereinfachtmax(a1, b1) < min(a2, b2)
, indem Sie einige Arithmetik speichern und mögliche Überläufe vermeiden (dies ist die Antwort von AX-Labs unten). In dem speziellen Fall, in dem Sie wissenb2-b1=a2-a1
, ist eine andere nützliche Neuanordnung der FloatingRock-Formelmax(a2, b2) - min(a1, b1) - (b2 - b1) < a2-a1
, die wirdabs(b1-a1) < a2 - a1
.Tolle Antwort von Simon , aber für mich war es einfacher, über den umgekehrten Fall nachzudenken.
Wann überlappen sich 2 Bereiche nicht? Sie überlappen sich nicht, wenn einer von ihnen beginnt, nachdem der andere endet:
Jetzt ist es einfach auszudrücken, wenn sie sich überschneiden:
quelle
Das Subtrahieren des Minimums der Enden der Bereiche vom Maximum des Anfangs scheint den Trick zu tun. Wenn das Ergebnis kleiner oder gleich Null ist, haben wir eine Überlappung. Dies macht es gut sichtbar:
quelle
Ich nehme an, die Frage betraf den schnellsten und nicht den kürzesten Code. Die schnellste Version muss Verzweigungen vermeiden, damit wir so etwas schreiben können:
für einen einfachen Fall:
oder für diesen Fall:
quelle
x1 <= y2 && y1 <= x2
enthält auch keine Verzweigungen , vorausgesetzt eine einigermaßen kompetente Compiler- und CPU-Architektur (auch im Jahr 2010). Tatsächlich ist auf x86 der generierte Code für den einfachen Ausdruck im Vergleich zum Code in dieser Antwort grundsätzlich identisch.quelle
x1 <= y1 && x2 >= y2 || x1 >= y1 && x2 <= y2
sollte auch true zurückgeben.Wenn Sie sich mit zwei Bereichen
[x1:x2]
und[y1:y2]
natürlichen / anti-natürlichen Ordnungsbereichen gleichzeitig befasst haben, in denen:x1 <= x2 && y1 <= y2
oderx1 >= x2 && y1 >= y2
Dann möchten Sie vielleicht Folgendes verwenden, um Folgendes zu überprüfen:
Sie überlappen sich <=>
(y2 - x1) * (x2 - y1) >= 0
wo nur vier Operationen beteiligt sind:
quelle
Wenn jemand nach einem Einzeiler sucht, der die tatsächliche Überlappung berechnet:
Wenn Sie ein paar weniger Operationen, aber ein paar mehr Variablen wollen:
quelle
Denken Sie umgekehrt : Wie lassen sich die beiden Bereiche nicht überlappen ? Gegeben
[x1, x2]
, dann[y1, y2]
sollte außerhalb sein[x1, x2]
, dhy1 < y2 < x1 or x2 < y1 < y2
was äquivalent zu isty2 < x1 or x2 < y1
.Daher überlappt sich die Bedingung, dass sich die beiden Bereiche überschneiden:
not(y2 < x1 or x2 < y1)
(entsprichty2 >= x1 and x2 >= y1
der akzeptierten Antwort von Simon).quelle
Sie haben bereits die effizienteste Darstellung - es ist das absolute Minimum, das überprüft werden muss, es sei denn, Sie wissen sicher, dass x1 <x2 usw. ist, und verwenden Sie dann die von anderen bereitgestellten Lösungen.
Sie sollten wahrscheinlich beachten, dass einige Compiler dies tatsächlich für Sie optimieren - indem sie zurückkehren, sobald einer dieser 4 Ausdrücke true zurückgibt. Wenn einer true zurückgibt, wird auch das Endergebnis angezeigt, sodass die anderen Überprüfungen einfach übersprungen werden können.
quelle
Mein Fall ist anders. Ich möchte überprüfen, ob sich zwei Zeitbereiche überschneiden. Es sollte keine zeitliche Überlappung geben. Hier ist die Go-Implementierung.
Testfälle
Sie können sehen, dass es im Grenzvergleich ein XOR-Muster gibt
quelle
Hier ist meine Version:
Sofern Sie keinen Hochleistungs-Bereichsprüfer für Milliarden von weit auseinander liegenden Ganzzahlen ausführen, sollten unsere Versionen eine ähnliche Leistung erbringen. Mein Punkt ist, das ist Mikrooptimierung.
quelle