it-swarm.com.de

Was ist der effizienteste Weg, um zwei ganzzahlige Bereiche auf Überlappung zu testen?

Mit zwei ganzzahligen Integerbereichen [x1: x2] und [y1: y2], wobei x1 ≤ x2 und y1 ≤ y2 ist, wie kann am besten getestet werden, ob sich die beiden Bereiche überlappen?

Eine einfache Implementierung sieht wie folgt aus:

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 rechne jedoch mit effizienteren Berechnungsmethoden.

Welche Methode wäre im Hinblick auf die wenigsten Operationen die effizienteste.

181
WilliamKF

Was bedeutet es, dass sich die Bereiche überschneiden? Dies bedeutet, dass es eine Zahl C gibt, die in beiden Bereichen liegt, d. H.

x1 <= C <= x2

und

y1 <= C <= y2

Wenn wir nun annehmen dürfen, dass die Bereiche wohlgeformt sind (so dass x1 <= x2 und y1 <= y2), dann reicht es aus zu testen

x1 <= y2 && y1 <= x2
345
Simon Nickerson

Gegeben zwei Bereiche [x1, x2], [y1, y2]

def is_overlapping(x1,x2,y1,y2):
    return max(x1,y1) <= min(x2,y2)
116
KFL

Dies kann ein normales menschliches Gehirn leicht verziehen, daher habe ich einen visuellen Ansatz gefunden, der einfacher zu verstehen ist:

Overlap madness

le Erklärung

Wenn zwei Bereiche "zu fett" sind, um in einen Schlitz zu passen, der genau die Summe der Breite von beiden ist, dann überlappen sie sich.

Für Bereiche [a1, a2] und [b1, b2] wäre dies:

/**
 * we are testing for:
 *     max point - min point < w1 + w2    
 **/
if max(a2, b2) - min(a1, b1) < (a2 - a1) + (b2 - b1) {
  // too fat -- they overlap!
}
40
FloatingRock

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 beendet ist:

dont_overlap = x2 < y1 || x1 > y2

Jetzt kann man leicht ausdrücken, wenn sie sich überschneiden:

overlap = !dont_overlap = !(x2 < y1 || x1 > y2) = (x2 >= y1 && x1 <= y2)
32
damluar

Das Abziehen des Minimums der Enden der Bereiche vom Maximum des Anfangs scheint den Trick auszuführen. Wenn das Ergebnis kleiner oder gleich Null ist, haben wir eine Überlappung. Dies visualisiert es gut:

 enter image description here

17
AXE-Labs

Ich denke, die Frage war nach dem schnellsten, nicht nach dem kürzesten Code. Die schnellste Version muss Verzweigungen vermeiden, sodass wir so etwas schreiben können:

für den einfachen Fall:

static inline bool check_ov1(int x1, int x2, int y1, int y2){
    // insetead of x1 < y2 && y1 < x2
    return (bool)(((unsigned int)((y1-x2)&(x1-y2))) >> (sizeof(int)*8-1));
};

oder für diesen Fall:

static inline bool check_ov2(int x1, int x2, int y1, int y2){
    // insetead of x1 <= y2 && y1 <= x2
    return (bool)((((unsigned int)((x2-y1)|(y2-x1))) >> (sizeof(int)*8-1))^1);
};
9
ruslik
return x2 >= y1 && x1 <= y2;

Wenn Sie sich mit zwei Bereichen [x1:x2] und [y1:y2] beschäftigen, werden gleichzeitig natürliche/anti-natürliche Ordnungsbereiche angegeben, wobei

  • natürliche Reihenfolge: x1 <= x2 && y1 <= y2 oder 
  • natürliche Reihenfolge: x1 >= x2 && y1 >= y2

dann können Sie dies zum Überprüfen verwenden:

sie überlappen sich <=> (y2 - x1) * (x2 - y1) >= 0

wenn nur vier Operationen betroffen sind: 

  • zwei Abzüge
  • eine Multiplikation
  • ein Vergleich 
2
Yankuan Zhang

Denken Sie auf die umgekehrte Weise : wie soll man die beiden Bereiche nicht überlappen ? Wenn [x1, x2] gegeben ist, sollte [y1, y2] außerhalb [x1, x2] sein, d. H. y1 < y2 < x1 or x2 < y1 < y2, was äquivalent zu y2 < x1 or x2 < y1 ist.

Daher überlappen sich die Bedingungen, um die beiden Bereiche zu machen: not(y2 < x1 or x2 < y1), was y2 >= x1 and x2 >= y1 entspricht (dies gilt auch für die von Simon akzeptierte Antwort).

0
Duke

Sie haben bereits die effizienteste Darstellung - es ist das absolute Minimum, das überprüft werden muss, wenn Sie nicht sicher sind, dass x1 <x2 usw. ist, und dann die Lösungen verwenden, die von anderen bereitgestellt wurden.

Sie sollten wahrscheinlich beachten, dass einige Compiler dies für Sie tatsächlich optimieren - indem Sie zurückkehren, sobald einer dieser 4 Ausdrücke true zurückgibt. Wenn einer den Wert true zurückgibt, wird auch das Endergebnis ausgegeben - die anderen Prüfungen können also einfach übersprungen werden.

0
Mark H

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.

    func CheckRange(as, ae, bs, be int) bool {
    return (as >= be) != (ae > bs)
    }

Testfälle

if CheckRange(2, 8, 2, 4) != true {
        t.Error("Expected 2,8,2,4 to equal TRUE")
    }

    if CheckRange(2, 8, 2, 4) != true {
        t.Error("Expected 2,8,2,4 to equal TRUE")
    }

    if CheckRange(2, 8, 6, 9) != true {
        t.Error("Expected 2,8,6,9 to equal TRUE")
    }

    if CheckRange(2, 8, 8, 9) != false {
        t.Error("Expected 2,8,8,9 to equal FALSE")
    }

    if CheckRange(2, 8, 4, 6) != true {
        t.Error("Expected 2,8,4,6 to equal TRUE")
    }

    if CheckRange(2, 8, 1, 9) != true {
        t.Error("Expected 2,8,1,9 to equal TRUE")
    }

    if CheckRange(4, 8, 1, 3) != false {
        t.Error("Expected 4,8,1,3 to equal FALSE")
    }

    if CheckRange(4, 8, 1, 4) != false {
        t.Error("Expected 4,8,1,4 to equal FALSE")
    }

    if CheckRange(2, 5, 6, 9) != false {
        t.Error("Expected 2,5,6,9 to equal FALSE")
    }

    if CheckRange(2, 5, 5, 9) != false {
        t.Error("Expected 2,5,5,9 to equal FALSE")
    }

sie können sehen, dass es ein XOR Muster im Grenzvergleich gibt

0
Ajeet47

Wenn jemand nach einem Einzeiler sucht, der die tatsächliche Überlappung berechnet:

int overlap = ( x2 > y1 || y2 < x1 ) ? 0 : (y2 >= y1 && x2 <= y1 ? y1 : y2) - ( x2 <= x1 && y2 >= x1 ? x1 : x2) + 1; //max 11 operations

Wenn Sie ein paar weniger Operationen wünschen, aber ein paar mehr Variablen:

bool b1 = x2 <= y1;
bool b2 = y2 >= x1;
int overlap = ( !b1 || !b2 ) ? 0 : (y2 >= y1 && b1 ? y1 : y2) - ( x2 <= x1 && b2 ? x1 : x2) + 1; // max 9 operations
0
Victor.dMdB