Trouver le XOR max de deux nombres dans un intervalle: peut-on faire mieux que quadratique?


14

Supposons que l'on nous donne deux nombres et et que nous voulons trouver pour l \ le i, \, j \ le r .lrmax(ij)li,jr

L'algorithme naïf vérifie simplement toutes les paires possibles; par exemple en rubis, nous aurions:

def max_xor(l, r)
  max = 0

  (l..r).each do |i|
    (i..r).each do |j|
      if (i ^ j > max)
        max = i ^ j
      end
    end
  end

  max
end

Je sens que nous pouvons faire mieux que quadratique. Existe-t-il un meilleur algorithme pour ce problème?


Vous devez laisser jcourir i+1..ret icourir l...r-1pour être précis.
Ahmet Alp Balkan

Réponses:


20

Nous pouvons atteindre un temps d'exécution linéaire dans la longueur de la représentation binaire de et :nlr

Le préfixe dans la représentation binaire de et , qui est le même pour les deux valeurs, est également le même pour toutes les valeurs entre elles. Ces bits seront donc toujours .plr0

Puisque , le bit suivant ce préfixe sera dans et dans . De plus, les nombres et sont tous deux dans l'intervalle.r>l1r0lp10n|p|1p01n|p|1

Le maximum que nous recherchons est donc .0|p|1n-|p|


1
Eh bien, c'était facile! Je suppose que j'aurais dû réfléchir davantage à ce problème.
Jacopo Notarstefano

Démarreur de fil a demandé "mieux que quadratique dans les chiffres". C'est linéaire dans la taille des nombres, donc c'est logarithmique dans les nombres eux-mêmes.
gnasher729

18

Il est possible de le faire en temps .O(Journalr)

Le XOR maximum possible de deux entiers quelconques à partir d'un intervalle peut être déterminé à partir de l r , en supposant que l , r soit des entiers. Cette valeur est égale à 2 p - 1 , où p est la plus petite valeur telle que 2 p soit supérieur à l r . [l,r]lrl,r2p-1p2plr

Voici une implémentation en C ++

int maximumXOR(int l, int r) {
    int q = l ^ r, a = 1;
    while(q){
        q /= 2;
        a <<= 1;
    }
    return --a;
}

Pouvez-vous expliquer la raison d'être de cet algorithme?
sk1pro99

Cette vidéo pourrait vous aider: youtube.com/watch?v=3j-ok4gMjXU
Jack Kinsella

0

Nous devons maximiser le xor entre «petit» et «haut». Prenons donc un exemple pour comprendre cela.

5 xor 2 = 101 xor 010 dans le premier cas: le bit MSB n'est pas défini pour les deux valeurs de la plage.Si vous voulez maximiser cela, ce que nous devons faire est de garder le MSB de 5 (100) tel qu'il est et de réfléchir à maximiser les bits inférieurs restants. Comme nous savons que les bits inférieurs seront tous un pour le cas où tout est 11, ce qui n'est que 3, c'est-à-dire 2 ^ 2-1. Puisque le problème parle de la plage entre 2 et 5, nous en avons certainement 3 dans la plage. Donc, tout ce que nous devons faire est de trouver l'ensemble MSB le plus élevé dans la plus grande des 2 valeurs et d'ajouter les 1 restants pour les bits inférieurs.

deuxième cas: Comme dans le cas où MSB est défini pour les deux valeurs de la plage, xor aura définitivement ces bits définis comme 0 et nous devons revenir aux bits inférieurs. Encore une fois pour les bits inférieurs, nous devons répéter la même logique que le premier cas. exemple: (10, 12) (1010, 1100) Comme vous pouvez le voir, les deux MSB sont définis sur 1, nous devons donc revenir aux bits inférieurs qui sont 010 et 100. Maintenant, ce problème est le même que dans le premier cas.

Il existe plusieurs façons de coder cela. Ce que j'ai fait, c'est de faire juste le xor entre «petit» et «haut» et cela supprimera le bit MSB si les bits «petit» et «haut» ont un bit MSB défini. Dans le cas contraire, il conservera le bit MSB. Après cela, j'essaie de faire tous les bits inférieurs 1 en trouvant la puissance maximale de 2 dans la sortie xorée et en soustrayant de 1.

def range_xor_max(small, high):
  if small == high:
    return 0
  xor = small ^ high
  #how many power of 2 is present
  how_many_power_of_2 = math.log(xor, 2)
  #we need to make all one's below the highest set bit
  return 2**int(math.floor(how_many_power_of_2)+1) - 1

0

Eh bien, vous pouvez utiliser le XOR de l et r pour trouver la réponse.

Supposons que l = 4 et r = 6.

l = 100, r = 110 (équivalents binaires de ces nombres)

l⊕r = 0 10

Cela signifie que la valeur maximale que vous recherchez aura certainement son premier bit (MSB) à zéro. (Pensez-y, est-il même possible que votre valeur maximale ait un 1 dans le premier bit? Si c'était 01010 et 00101, le xor aurait été = 01 111, c'est-à-dire que la valeur maximale entre 01010 et 00101 aura certainement un 1 dans leur deuxième bit de gauche, il n'est pas possible d'obtenir un 1 avant le deuxième bit de gauche c'est-à-dire dans le premier bit de gauche)

Il vous reste donc les 2 bits restants pour trouver le maximum. Nous savons que la valeur maximale possible lorsque nous avons n bits avec nous est = 2 n -1, donc la réponse dans ce cas sera 2 2 -1 = 4-1 = 3.

À partir de l'exemple ci-dessus, nous pouvons faire un algorithme général pour cela.

Étape 1. num = nombre de bits requis pour représenter max ( l , r )

Étape 2. res = lr

Étape 3. pos = position du premier bit qui est défini à partir de la gauche dans res (indexation basée sur 0)

Étape 4. n = num - pos

Étape 5. ans = 2 n −1

Complexité temporelle = O (n)


-1

Pour chaque chiffre binaire, il existe 4 possibilités: 1_and_1, 1_and_0, 0_and_1 ou 0_and_0. Les chiffres inférieurs possibles ne font pas ou peu de différence dans la sortie xor de choix du chiffre suivant. Le meilleur algorithme possible est d'ignorer tous les chiffres inférieurs et de ne considérer que les 2 suivants disponibles, étant donné les choix précédents concernant les chiffres supérieurs. S'il s'agit de 1_and_1 ou 0_and_0, le choix est clair, mais si ce chiffre est 1_and_0 vs 0_and_1 (qui ont une valeur xor mais inégale), alors de manière récursive, il devrait être égal à l' algorithme https://en.wikipedia.org/wiki/Edit_distance , ce qui signifie le pire cas de journal au carré.


1
Je ne suis pas sûr de ce que vous entendez par «chiffre inférieur», «petit journal de fuite» ou «cela ... signifiant le pire cas de journal au carré». Pourriez-vous clarifier?
David Richerby

-1

Pour les intervalles de 32 bits, je suis juste tombé sur cette O(1)solution sur les éditoriaux de Hacker Rank. Je n'ai aucune idée de comment cela fonctionne, mais cela fonctionne. (Peut-être que quelqu'un peut expliquer pourquoi cela fonctionne.)

def max_xor(L,R):
  v = L^R
  v |= v >> 1
  v |= v >> 2
  v |= v >> 4
  v |= v >> 8
  v |= v >> 16
  return b

Source: https://www.hackerrank.com/challenges/maximizing-xor/editorial


2
En quoi votre réponse (après correction) diffère-t-elle de ysb.4 (en plus, il a expliqué ce qui se passe)? Que fait le «retour b» avec le «b» non déclaré? Et désolé, mais je ne peux pas accéder au lien que vous avez fourni.
Evil
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.