Dado dois intervalos inteiros inclusivos [x1: x2] e [y1: y2], onde x1 ≤ x2 e y1 ≤ y2, qual é a maneira mais eficiente de testar se existe alguma sobreposição dos dois intervalos?
Uma implementação simples é a seguinte:
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);
}
Mas espero que haja maneiras mais eficientes de calcular isso.
Qual método seria o mais eficiente em termos de menos operações.
performance
comparison
integer
range
WilliamKF
fonte
fonte
Respostas:
O que significa que os intervalos se sobrepõem? Isso significa que existe algum número C que está em ambos os intervalos, ou seja,
e
Agora, se pudermos assumir que os intervalos estão bem formados (de modo que x1 <= x2 e y1 <= y2), então é suficiente testar
fonte
x1 <= y2 && y1 >= x2
, não?Dado dois intervalos [x1, x2], [y1, y2]
fonte
min(x2,y2) - max(x1,y1)
fornece a quantidade de sobreposição, caso você precise.Isso pode deformar facilmente um cérebro humano normal, então achei uma abordagem visual mais fácil de entender:
le Explicação
Se dois intervalos são "muito gordos" para caber em um slot que é exatamente a soma da largura de ambos, eles se sobrepõem.
Para intervalos
[a1, a2]
e[b1, b2]
isso seria:fonte
a2 - a1 + b2 - b1
pode transbordar. Para corrigi-lo, reorganize a fórmula paramax(a2, b2) - a2 - b2 < min(a1, b1) - a1 - b1
, o que simplificamax(a1, b1) < min(a2, b2)
, economizando aritmética e evitando possíveis estouros (esta é a resposta do AX-Labs abaixo). No caso especial em que você sabeb2-b1=a2-a1
, outro rearranjo útil da fórmula de FloatingRock émax(a2, b2) - min(a1, b1) - (b2 - b1) < a2-a1
, que se tornaabs(b1-a1) < a2 - a1
.Ótima resposta de Simon , mas para mim foi mais fácil pensar em caso inverso.
Quando 2 faixas não se sobrepõem? Eles não se sobrepõem quando um deles começa depois que o outro termina:
Agora é fácil expressar quando eles se sobrepõem:
fonte
Subtrair o mínimo dos fins dos intervalos do máximo do início parece ser suficiente. Se o resultado for menor ou igual a zero, temos uma sobreposição. Isso visualiza bem:
fonte
Suponho que a pergunta era sobre o código mais rápido, não o mais curto. A versão mais rápida precisa evitar ramificações, para que possamos escrever algo como isto:
para casos simples:
ou, para este caso:
fonte
x1 <= y2 && y1 <= x2
também não possui ramificações , assumindo um compilador e uma arquitetura de CPU razoavelmente competentes (mesmo em 2010). De fato, no x86, o código gerado é basicamente idêntico para a expressão simples versus o código nesta resposta.fonte
x1 <= y1 && x2 >= y2 || x1 >= y1 && x2 <= y2
também deve retornar verdadeiro.Se você estava lidando com, dado dois intervalos
[x1:x2]
e[y1:y2]
, ordem natural / antinatural varia ao mesmo tempo em que:x1 <= x2 && y1 <= y2
oux1 >= x2 && y1 >= y2
você pode usar isso para verificar:
eles estão sobrepostos <=>
(y2 - x1) * (x2 - y1) >= 0
onde apenas quatro operações estão envolvidas:
fonte
Se alguém estiver procurando por uma linha que calcule a sobreposição real:
Se você deseja menos operações, mas mais algumas variáveis:
fonte
Pense de maneira inversa : como fazer as duas faixas não se sobreporem ? Dado
[x1, x2]
, então[y1, y2]
deve estar fora[x1, x2]
, ou seja, oy1 < y2 < x1 or x2 < y1 < y2
que equivale ay2 < x1 or x2 < y1
.Portanto, a condição para fazer os 2 intervalos se sobrepõe:, o
not(y2 < x1 or x2 < y1)
que é equivalente ay2 >= x1 and x2 >= y1
(o mesmo com a resposta aceita por Simon).fonte
Você já tem a representação mais eficiente - é o mínimo necessário que deve ser verificado, a menos que você tenha certeza de que x1 <x2 etc, e use as soluções fornecidas por outras pessoas.
Você provavelmente deve observar que alguns compiladores realmente otimizarão isso para você - retornando assim que qualquer uma dessas 4 expressões retornar verdadeira. Se um retornar verdadeiro, o resultado final será o mesmo - para que as outras verificações possam ser ignoradas.
fonte
Meu caso é diferente. Eu quero verificar dois intervalos de tempo se sobrepõem. não deve haver sobreposição de tempo unitário. aqui está a implementação Go.
Casos de teste
você pode ver que existe um padrão XOR na comparação de limites
fonte
Aqui está a minha versão:
A menos que você esteja executando um verificador de intervalo de alto desempenho em bilhões de números inteiros com espaçamento amplo, nossas versões deverão ter o mesmo desempenho. O que quero dizer é que isso é micro-otimização.
fonte