Trovare il massimo XOR di due numeri in un intervallo: possiamo fare meglio del quadratico?


14

Supponiamo stiamo dato due numeri l e e che vogliamo trovare per l \ le i, \, j \ le r .rmax(ij)li,jr

L'algoritmo ingenuo controlla semplicemente tutte le coppie possibili; ad esempio in ruby ​​avremmo:

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

Ho la sensazione che possiamo fare meglio di secondo grado. Esiste un algoritmo migliore per questo problema?


Dovresti lasciar jpassare i+1..re icorrere l...r-1per essere precisi.
Ahmet Alp Balkan,

Risposte:


20

Possiamo raggiungere runtime lineare nella lunghezza della rappresentazione binaria di e :nlr

Il prefisso nella rappresentazione binaria di e , che è la stessa per entrambi i valori, è anche lo stesso per tutti i valori tra loro. Quindi questi bit saranno sempre .plr0

Poiché , il bit seguente questo prefisso sarà a e in . Inoltre, i numeri e sono entrambi nell'intervallo.r>l1r0lp10n|p|1p01n|p|1

Quindi il massimo che stiamo cercando è .0|p|1n|p|


1
Bene, è stato facile! Immagino che avrei dovuto pensare più a questo problema.
Jacopo Notarstefano,

L'avviatore di discussione ha chiesto "meglio di quadratico nei numeri". Questo è lineare nella dimensione dei numeri, quindi è logaritmico nei numeri stessi.
gnasher729,

18

È possibile farlo in tempo .O(logr)

Il massimo XOR possibile di due numeri interi qualsiasi da un intervallo può essere determinato da l r , assumendo che l , r siano numeri interi. Questo valore è uguale a 2 p - 1 , dove p è il valore più piccolo in modo che 2 p sia maggiore di l r . [l,r]lrl,r2p1p2plr

Ecco un'implementazione in C ++

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

Puoi spiegare la logica alla base di questo algoritmo?
sk1pro99

Questo video potrebbe aiutarti: youtube.com/watch?v=3j-ok4gMjXU
Jack Kinsella

0

Dobbiamo massimizzare lo xor tra "piccolo" e "alto". Facciamo un esempio per capirlo.

5 xo 2 = 101 xo 010 primo caso: il bit MSB non è impostato per entrambi i valori nell'intervallo. Se si desidera massimizzare questo, ciò che dobbiamo fare è mantenere l'MSB di 5 (100) così com'è e pensare massimizzando i bit inferiori rimanenti. Come sappiamo che i bit più bassi saranno tutti uno per il caso in cui tutto è 11, che non è altro che 3, ovvero 2 ^ 2-1. Poiché il problema sta parlando dell'intervallo tra 2 e 5, abbiamo sicuramente 3 nell'intervallo. Quindi tutto ciò che dobbiamo fare è scoprire il set di MSB più alto nel più grande dei 2 valori e aggiungere i rimanenti 1 per i bit inferiori.

secondo caso: per quanto riguarda il caso in cui MSB sia impostato per entrambi i valori nell'intervallo che fa xor avremo sicuramente quei bit impostati come 0 e dobbiamo tornare ai bit più bassi. Anche in questo caso per bit inferiori dobbiamo ripetere la stessa logica del primo caso. esempio: (10, 12) (1010, 1100) Come puoi vedere entrambi hanno MSB impostato su 1, allora dobbiamo tornare ai bit inferiori che sono 010 e 100. Ora questo problema è lo stesso del primo caso.

Esistono diversi modi per codificare questo. Quello che ho fatto è stato fare solo lo xor tra "piccolo" e "alto" e questo rimuoverà il bit MSB se sia "piccolo" che "alto" hanno impostato il bit MSB. In caso contrario, verrà preservato il bit MSB. Dopo quello sto provando a fare tutti i bit più bassi 1 scoprendo la potenza massima di 2 nell'uscita xored e sottraendo da 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

Beh, è possibile utilizzare la XOR di L e r per trovare la risposta.

Supponiamo che l = 4 e r = 6.

l = 100, r = 110 (equivalenti binari di questi numeri)

l⊕r = 0 10

Ciò significa che il valore massimo che stai cercando avrà sicuramente il suo primo bit (MSB) come zero. (Pensaci, è anche possibile che il tuo valore massimo abbia un 1 nel primo bit? Se fosse 01010 e 00101, lo xor sarebbe stato = 01 111, ovvero il valore massimo tra 01010 e 00101 avrà sicuramente un 1 nel loro secondo bit da sinistra, non è possibile ottenere un 1 prima del secondo bit da sinistra, cioè nel primo bit da sinistra)

Quindi, ti rimangono i restanti 2 bit per trovare il massimo. Sappiamo che il valore massimo possibile quando abbiamo n bit con noi è = 2 n −1, quindi la risposta in questo caso sarà 2 2 -1 = 4-1 = 3.

Dall'esempio sopra, possiamo creare un algoritmo generale per questo.

Passaggio 1. num = numero di bit richiesti per rappresentare max ( l , r )

Passaggio 2. res = lr

Passaggio 3. pos = Posizione del primo bit impostato da sinistra in res (indicizzazione basata su 0)

Passaggio 4. n = num - pos

Passaggio 5. ans = 2 n −1

Complessità temporale = O (n)


-1

Per ogni cifra binaria, ci sono 4 possibilità: 1_e_1, 1_e_0, 0_e_1 o 0_e_0. Le possibili cifre inferiori non fanno alcuna differenza o log-vanishingly piccola per l'output xor di scelta della cifra successiva. Il miglior algoritmo possibile è ignorare tutte le cifre inferiori e considerare solo le successive 2 disponibili, date le precedenti scelte sulle cifre più alte. Se questo è 1_and_1 o 0_and_0, la scelta è chiara, ma se questa cifra è 1_and_0 vs 0_and_1 (che hanno lo stesso valore xor ma diseguale) allora ricorsivamente dovrebbe essere uguale all'algoritmo https://en.wikipedia.org/wiki/Edit_distance , significa peggior caso di log al quadrato.


1
Non sono sicuro di cosa intendi per "cifra inferiore", "log-vanishingly-small" o "esso ... che significa il peggior caso di log al quadrato". Potresti chiarire?
David Richerby,

-1

Per intervalli di 32 bit, ho appena trovato questa O(1)soluzione negli editoriali di Hacker Rank. Non ho idea di come funzioni, ma funziona. (Forse qualcuno può spiegare perché funziona.)

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

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


2
In che modo la tua risposta (dopo la correzione) differisce da quella di ysb.4 (oltre a spiegare cosa sta succedendo)? Che cosa fa "return b" con "b" non dichiarato? E mi dispiace, ma non riesco ad accedere al link che hai fornito.
Evil
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.