web-dev-qa-db-fra.com

Quel est le moyen le plus efficace de tester le chevauchement de deux plages entières?

Étant donné deux plages entières inclusives [x1: x2] et [y1: y2], où x1 ≤ x2 et y1 ≤ y2, quel est le moyen le plus efficace de vérifier s'il existe un chevauchement des deux plages?

Une implémentation simple est la suivante:

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);
}

Mais je pense qu’il existe des moyens plus efficaces de calculer cela.

Quelle méthode serait la plus efficace en termes de moins d'opérations.

181
WilliamKF

Qu'est-ce que cela signifie pour les gammes de se chevaucher? Cela signifie qu’il existe un nombre C qui se situe dans les deux plages, c.-à-d.

x1 <= C <= x2

et

y1 <= C <= y2

Maintenant, si on nous laisse supposer que les plages sont bien formées (pour que x1 <= x2 et y1 <= y2), il suffit alors

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

Étant donné deux plages [x1, x2], [y1, y2]

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

Cela peut facilement déformer un cerveau humain normal, alors j'ai trouvé une approche visuelle plus facile à comprendre:

Overlap madness

le Explication

Si deux plages sont "trop ​​grosse" pour tenir dans un emplacement qui correspond exactement à la somme de la largeur des deux, elles se chevauchent.

Pour les plages [a1, a2] et [b1, b2], ce serait:

/**
 * 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

Excellente réponse de Simon , mais pour moi, il était plus facile de penser au cas inverse.

Quand 2 plages ne se chevauchent pas? Ils ne se chevauchent pas lorsque l’un d’entre eux commence après l’autre:

dont_overlap = x2 < y1 || x1 > y2

Maintenant, il est facile d’exprimer quand ils se chevauchent:

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

Soustraire le minimum des extrémités des plages du maximum du début semble faire l'affaire. Si le résultat est inférieur ou égal à zéro, nous avons un chevauchement. Cela le visualise bien:

 enter image description here

17
AXE-Labs

Je suppose que la question portait sur le code le plus rapide et non le plus court. La version la plus rapide doit éviter les branches, nous pouvons donc écrire quelque chose comme ceci:

pour un cas simple:

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));
};

ou, dans ce cas:

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;

Si vous avez affaire à deux plages [x1:x2] et [y1:y2], plages d'ordre naturel/anti-naturel en même temps:

  • ordre naturel: x1 <= x2 && y1 <= y2 ou 
  • ordre anti-naturel: x1 >= x2 && y1 >= y2

alors vous voudrez peut-être utiliser ceci pour vérifier:

ils se chevauchent <=> (y2 - x1) * (x2 - y1) >= 0

où seulement quatre sont impliqués: 

  • deux soustractions
  • une multiplication
  • une comparaison 
2
Yankuan Zhang

Pensez de la manière inverse: comment faire en sorte que les 2 plages ne se chevauchent pas? Étant donné [x1, x2], alors [y1, y2] devrait être extérieur[x1, x2], c'est-à-dire y1 < y2 < x1 or x2 < y1 < y2, ce qui équivaut à y2 < x1 or x2 < y1.

Par conséquent, la condition pour que les 2 plages se chevauchent: not(y2 < x1 or x2 < y1), ce qui équivaut à y2 >= x1 and x2 >= y1 (identique à la réponse acceptée par Simon).

0
Duke

Vous avez déjà la représentation la plus efficace - c'est le strict minimum qui doit être vérifié, sauf si vous êtes certain que x1 <x2 etc.

Vous devriez probablement noter que certains compilateurs vont réellement optimiser cela pour vous - en retournant dès que l'une de ces 4 expressions retourne true. Si l'une des réponses est vraie, le résultat final le sera également - les autres vérifications pourront simplement être ignorées.

0
Mark H

Mon cas est différent. Je veux vérifier deux plages de temps se chevauchent. il ne devrait pas y avoir de chevauchement d'unité de temps. voici l'implémentation de Go.

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

Cas de test

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")
    }

vous pouvez voir qu'il y a un motif XOR dans la comparaison des limites

0
Ajeet47

Si quelqu'un recherche un one-line qui calcule le chevauchement réel:

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

Si vous voulez quelques opérations en moins, mais quelques variables en plus:

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