Biorąc pod uwagę dwa całkowite zakresy liczb całkowitych [x1: x2] i [y1: y2], gdzie x1 ≤ x2 i y1 ≤ y2, jaki jest najskuteczniejszy sposób sprawdzenia, czy oba zakresy się pokrywają?
Prosta implementacja wygląda następująco:
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);
}
Ale oczekuję, że istnieją bardziej wydajne sposoby na obliczenie tego.
Która metoda byłaby najbardziej wydajna pod względem najmniejszej liczby operacji.
performance
comparison
integer
range
WilliamKF
źródło
źródło
Odpowiedzi:
Co to znaczy, że zakresy się pokrywają? Oznacza to, że istnieje pewna liczba C, która znajduje się w obu zakresach, tj
i
Teraz, jeśli możemy założyć, że zakresy są dobrze uformowane (tak, że x1 <= x2 i y1 <= y2), wystarczy przetestować
źródło
x1 <= y2 && y1 >= x2
, nie?Biorąc pod uwagę dwa zakresy [x1, x2], [y1, y2]
źródło
min(x2,y2) - max(x1,y1)
zapewnia to nakładanie się w razie potrzeby.Może to łatwo wypaczyć normalny ludzki mózg, więc znalazłem wizualne podejście, które jest łatwiejsze do zrozumienia:
le Wyjaśnienie
Jeśli dwa zakresy są „zbyt grube”, aby zmieścić się w szczelinie, która jest dokładnie sumą szerokości obu, wówczas się pokrywają.
Dla zakresów
[a1, a2]
i[b1, b2]
to byłoby:źródło
a2 - a1 + b2 - b1
może się przepełnić. Aby to naprawić, przestaw formułę namax(a2, b2) - a2 - b2 < min(a1, b1) - a1 - b1
, co upraszczamax(a1, b1) < min(a2, b2)
, oszczędzając trochę arytmetyki i unikając ewentualnych przelewów (oto odpowiedź AX-Labs poniżej). W szczególnym przypadku, w którym wieszb2-b1=a2-a1
, kolejną przydatną zmianą formuły FloatingRock jestmax(a2, b2) - min(a1, b1) - (b2 - b1) < a2-a1
, która staje sięabs(b1-a1) < a2 - a1
.Świetna odpowiedź od Simona , ale dla mnie łatwiej było pomyśleć o odwrotnej sprawie.
Kiedy 2 zakresy się nie pokrywają? Nie nakładają się, gdy jeden z nich zaczyna się po zakończeniu drugiego:
Teraz łatwo wyrazić, kiedy się pokrywają:
źródło
Wydaje się, że odjęcie minimum końca przedziałów od maksimum początku jest wystarczające. Jeśli wynik jest mniejszy lub równy zeru, nakładamy się. To dobrze to wizualizuje:
źródło
Przypuszczam, że pytanie dotyczyło najszybszego, a nie najkrótszego kodu. Najszybsza wersja musi unikać gałęzi, więc możemy napisać coś takiego:
dla prostego przypadku:
lub w tym przypadku:
źródło
x1 <= y2 && y1 <= x2
nie ma też żadnych rozgałęzień , przy założeniu, że kompilator i architektura procesora są odpowiednio kompetentne (nawet w 2010 r.). W rzeczywistości na x86 wygenerowany kod jest zasadniczo identyczny dla prostego wyrażenia vs. kod w tej odpowiedzi.źródło
x1 <= y1 && x2 >= y2 || x1 >= y1 && x2 <= y2
powinien również zwrócić true.Jeśli miałeś do czynienia z dwoma zakresami
[x1:x2]
i[y1:y2]
naturalnymi / antynaturalnymi zakresami zamówień jednocześnie:x1 <= x2 && y1 <= y2
lubx1 >= x2 && y1 >= y2
możesz użyć tego do sprawdzenia:
nakładają się na siebie <=>
(y2 - x1) * (x2 - y1) >= 0
przy zaangażowaniu tylko czterech operacji:
źródło
Jeśli ktoś szuka jednej linijki, która oblicza faktyczne nakładanie się:
Jeśli chcesz kilka operacji mniej, ale kilka innych zmiennych:
źródło
Pomyśl odwrotnie : jak sprawić, by 2 zakresy się nie nakładały ? Biorąc pod uwagę
[x1, x2]
,[y1, y2]
powinien być na zewnątrz[x1, x2]
, tj.y1 < y2 < x1 or x2 < y1 < y2
Co jest równoważney2 < x1 or x2 < y1
.Dlatego warunek, aby 2 zakresy zachodziły na siebie:,
not(y2 < x1 or x2 < y1)
co jest równoważney2 >= x1 and x2 >= y1
(to samo z zaakceptowaną odpowiedzią Simona).źródło
Masz już najbardziej wydajną reprezentację - to absolutne minimum, które należy sprawdzić, chyba że wiesz na pewno, że x1 <x2 itp., A następnie skorzystaj z rozwiązań dostarczonych przez innych.
Powinieneś prawdopodobnie zauważyć, że niektóre kompilatory faktycznie zoptymalizują to dla Ciebie - zwracając, gdy tylko jedno z tych 4 wyrażeń zwróci wartość true. Jeśli jedna zwróci wartość true, wynik będzie taki sam - a pozostałe kontrole można po prostu pominąć.
źródło
Moja sprawa jest inna. Chcę sprawdzić, czy dwa zakresy czasu się pokrywają. czas nie powinien nakładać się na siebie. oto implementacja Go.
Przypadki testowe
widać porównanie XOR w porównaniu granic
źródło
Oto moja wersja:
Jeśli nie korzystasz z wysokowydajnego sprawdzania zasięgu na miliardach liczb całkowitych o dużej odległości, nasze wersje powinny działać podobnie. Chodzi mi o to, że jest to mikrooptymalizacja.
źródło