Dados dos rangos enteros inclusivos [x1: x2] y [y1: y2], donde x1 ≤ x2 e y1 ≤ y2, ¿cuál es la forma más eficiente de probar si hay una superposición de los dos rangos?
Una implementación simple es la siguiente:
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);
}
Pero espero que haya formas más eficientes de calcular esto.
Qué método sería el más eficiente en términos de la menor cantidad de operaciones.
performance
comparison
integer
range
WilliamKF
fuente
fuente
Respuestas:
¿Qué significa que los rangos se superpongan? Significa que existe algún número C que está en ambos rangos, es decir
y
Ahora, si se nos permite suponer que los rangos están bien formados (de modo que x1 <= x2 e y1 <= y2), entonces es suficiente probar
fuente
x1 <= y2 && y1 >= x2
, ¿no?Dados dos rangos [x1, x2], [y1, y2]
fuente
min(x2,y2) - max(x1,y1)
proporciona la cantidad de superposición en caso de que lo necesite.Esto puede deformar fácilmente un cerebro humano normal, por lo que he encontrado un enfoque visual que es más fácil de entender:
le Explicación
Si dos rangos son "demasiado gruesos" para caber en una ranura que es exactamente la suma del ancho de ambos, entonces se superponen.
Para rangos
[a1, a2]
y[b1, b2]
esto sería:fuente
a2 - a1 + b2 - b1
puede desbordarse. Para solucionarlo, reorganice la fórmula amax(a2, b2) - a2 - b2 < min(a1, b1) - a1 - b1
, que se simplificamax(a1, b1) < min(a2, b2)
, ahorrando algo de aritmética y evitando posibles desbordamientos (esta es la respuesta de AX-Labs a continuación). En el caso especial donde sabesb2-b1=a2-a1
, otra reorganización útil de la fórmula de FloatingRock esmax(a2, b2) - min(a1, b1) - (b2 - b1) < a2-a1
, que se convierte enabs(b1-a1) < a2 - a1
.Gran respuesta de Simon , pero para mí fue más fácil pensar en el caso inverso.
¿Cuándo no se superponen 2 rangos? No se superponen cuando uno de ellos comienza después de que el otro termina:
Ahora es fácil expresar cuándo se superponen:
fuente
Restar el mínimo de los extremos de los rangos del máximo del principio parece ser el truco. Si el resultado es menor o igual a cero, tenemos una superposición. Esto lo visualiza bien:
fuente
Supongo que la pregunta era sobre el código más rápido, no el más corto. La versión más rápida tiene que evitar las ramas, por lo que podemos escribir algo como esto:
por simple caso:
o, para este caso:
fuente
x1 <= y2 && y1 <= x2
tampoco tiene ramificaciones , suponiendo un compilador razonablemente competente y una arquitectura de CPU (incluso en 2010). De hecho, en x86, el código generado es básicamente idéntico para la expresión simple frente al código en esta respuesta.fuente
x1 <= y1 && x2 >= y2 || x1 >= y1 && x2 <= y2
también debería volver cierto.Si estaba lidiando, dados dos rangos
[x1:x2]
y rangos de orden[y1:y2]
natural / antinatural al mismo tiempo donde:x1 <= x2 && y1 <= y2
ox1 >= x2 && y1 >= y2
entonces es posible que desee usar esto para verificar:
se superponen <=>
(y2 - x1) * (x2 - y1) >= 0
donde solo participan cuatro operaciones:
fuente
Si alguien está buscando una línea que calcule la superposición real:
Si desea un par de operaciones menos, pero un par de variables más:
fuente
Piense de manera inversa : ¿cómo hacer que los 2 rangos no se superpongan ? Dado
[x1, x2]
, entonces[y1, y2]
debe estar afuera[x1, x2]
, es decir,y1 < y2 < x1 or x2 < y1 < y2
que es equivalente ay2 < x1 or x2 < y1
.Por lo tanto, la condición para hacer que los 2 rangos se superpongan:
not(y2 < x1 or x2 < y1)
es equivalente ay2 >= x1 and x2 >= y1
(lo mismo con la respuesta aceptada por Simon).fuente
Ya tiene la representación más eficiente: es el mínimo necesario que debe verificarse a menos que sepa con certeza que x1 <x2, etc., luego use las soluciones que otros han proporcionado.
Probablemente debería tener en cuenta que algunos compiladores realmente optimizarán esto para usted, al regresar tan pronto como cualquiera de esas 4 expresiones devuelva verdadero. Si uno devuelve verdadero, también lo hará el resultado final, por lo que las otras verificaciones solo se pueden omitir.
fuente
Mi caso es diferente. Quiero comprobar la superposición de dos rangos de tiempo. no debe haber una superposición de unidad de tiempo. aquí está la implementación de Go.
Casos de prueba
puedes ver que hay un patrón XOR en la comparación de límites
fuente
Aquí está mi versión:
A menos que esté ejecutando un comprobador de rango de alto rendimiento en miles de millones de enteros ampliamente espaciados, nuestras versiones deberían funcionar de manera similar. Mi punto es que esto es micro-optimización.
fuente