Finden des maximalen XOR von zwei Zahlen in einem Intervall: Können wir es besser machen als quadratisch?


14

Nehmen wir an, wir haben zwei Zahlen l und und wollen für l \ le i, \, j \ le r finden .max ( i j ) l i ,rmax(ij)li,jr

Der naive Algorithmus überprüft einfach alle möglichen Paare; Zum Beispiel in Ruby hätten wir:

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

Ich spüre, dass wir es besser als quadratisch machen können. Gibt es einen besseren Algorithmus für dieses Problem?


Sie sollten jlaufen i+1..rund ilaufen lassen l...r-1, um genau zu sein.
Ahmet Alp Balkan

Antworten:


20

Wir können eine lineare Laufzeit in der Länge der binären Darstellung von l und r erreichen :nlr

Das Präfix in der Binärdarstellung von l und r , das für beide Werte gleich ist, ist auch für alle Werte zwischen ihnen gleich. Diese Bits werden also immer 0 sein .plr0

Da , ist das diesem Präfix folgende Bit 1 in r und 0 in l . Weiterhin sind die Zahlen p 10 n - | p | - 1 und p 01 n - | p | - 1 sind beide in der Pause.r>l1r0lp10n|p|1p01n|p|1

Das gesuchte Maximum ist also .0|p|1n|p|


1
Das war ganz einfach! Ich denke, ich hätte über dieses Problem mehr nachdenken sollen.
Jacopo Notarstefano

Threadstarter fragte nach "besser als quadratisch in den Zahlen". Dies ist in der Größe der Zahlen linear, so dass es in den Zahlen selbst logarithmisch ist.
gnasher729

18

Es ist möglich, dies in Zeit zu tun .O(logr)

Das maximal mögliche XOR von zwei beliebigen ganzen Zahlen aus einem Intervall kann aus l r unter der Annahme bestimmt werden , dass l , r ganze Zahlen sind. Dieser Wert ist gleich 2 p - 1 , wobei p der kleinste Wert ist, so dass 2 p größer als l r ist . [l,r]lrl,r2p1p2plr

Hier ist eine Implementierung in C ++

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

Können Sie die Gründe für diesen Algorithmus erklären?
sk1pro99

Dieses Video könnte dir helfen: youtube.com/watch?v=3j-ok4gMjXU
Jack Kinsella

0

Wir müssen das xor zwischen "klein" und "hoch" maximieren. Nehmen wir also ein Beispiel, um dies zu verstehen.

5 xor 2 = 101 xor 010 erster Fall: MSB-Bit ist nicht für beide Werte im Bereich gesetzt. Wenn dies maximiert werden soll, müssen wir das MSB von 5 (100) so belassen, wie es ist, und darüber nachdenken Maximieren der verbleibenden unteren Bits. Wie wir wissen, sind niedrigere Bits alle eins für den Fall, dass alles 11 ist, was nichts anderes als 3 ist, dh 2 ^ 2-1. Da es sich bei dem Problem um einen Bereich zwischen 2 und 5 handelt, haben wir definitiv 3 im Bereich. Wir müssen also nur den höchsten MSB-Satz im größeren von 2 Werten herausfinden und die verbleibenden Einsen für die unteren Bits hinzufügen.

Zweiter Fall: Wie für den Fall, dass MSB für beide Werte in dem Bereich gesetzt ist, in dem xor ausgeführt wird, werden diese Bits auf jeden Fall auf 0 gesetzt, und wir müssen zu niedrigeren Bits zurückkehren. Auch für niedrigere Bits müssen wir die gleiche Logik wie im ersten Fall wiederholen. Beispiel: (10, 12) (1010, 1100) Wie Sie sehen können, haben beide MSB auf 1 gesetzt, dann müssen wir zu niedrigeren Bits zurückkehren, nämlich 010 und 100. Jetzt ist dieses Problem dasselbe wie im ersten Fall.

Es gibt verschiedene Möglichkeiten, dies zu codieren. Was ich getan habe, ist, nur das xor zwischen "klein" und "hoch" zu machen, und das wird das MSB-Bit entfernen, wenn sowohl "klein" als auch "hoch" das MSB-Bit gesetzt haben. Ist dies nicht der Fall, wird das MSB-Bit beibehalten. Danach versuche ich, alle niedrigeren Bits zu 1 zu machen, indem ich die maximale Potenz von 2 in der xored Ausgabe herausfinde und von 1 subtrahiere.

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

Nun, Sie können das XOR von l und r verwenden , um die Antwort zu finden.

Angenommen, l = 4 und r = 6.

l = 100, r = 110 (binäre Äquivalente dieser Zahlen)

l⊕r = 0 10

Dies bedeutet, dass für den gesuchten Maximalwert das erste Bit (MSB) definitiv Null ist. (Denken Sie darüber nach, ist es sogar möglich, dass Ihr Maximalwert stattdessen eine 1 im ersten Bit hat? Wenn es 01010 und 00101 waren, wäre das xor = 01 111 gewesen, dh der Maximalwert zwischen 01010 und 00101 wird definitiv sein eine 1 in ihrem zweiten Bit von links, es ist nicht möglich, eine 1 vor dem zweiten Bit von links zu bekommen, dh im ersten Bit von links)

Sie haben also die verbleibenden 2 Bits, um das Maximum zu finden. Wir wissen, dass der maximal mögliche Wert, wenn wir n Bits bei uns haben, = 2 n −1 ist, daher lautet die Antwort in diesem Fall 2 2 -1 = 4-1 = 3.

Aus dem obigen Beispiel können wir einen allgemeinen Algorithmus dafür erstellen.

Schritt 1. num = Anzahl der zur Darstellung von max ( l , r ) erforderlichen Bits

Schritt 2. res = lr

Schritt 3. pos = Position des ersten Bits, das in res von links gesetzt wird (0-basierte Indizierung)

Schritt 4. n = num - pos

Schritt 5. ans = 2 n −1

Zeitkomplexität = O (n)


-1

Für jede Binärzahl gibt es 4 Möglichkeiten: 1_und_1, 1_und_0, 0_und_1 oder 0_und_0. Die möglichen niedrigeren Stellen machen keinen oder nur einen geringfügigen Unterschied zu der von Ihnen gewählten xor-Ausgabe der nächsten Stelle. Der bestmögliche Algorithmus besteht darin, alle niedrigeren Stellen zu ignorieren und nur die nächsten 2 verfügbaren Stellen zu berücksichtigen, vorausgesetzt, Sie haben zuvor eine Auswahl über höhere Stellen getroffen. Wenn dies 1_und_1 oder 0_und_0 ist, ist die Wahl klar, aber wenn diese Ziffer 1_und_0 gegen 0_und_1 ist (die das gleiche x oder aber einen ungleichen Wert haben), sollte sie rekursiv dem https://en.wikipedia.org/wiki/Edit_distance-Algorithmus entsprechen . was bedeutet, schlimmsten Fall von Log im Quadrat.


1
Ich bin mir nicht sicher, was Sie mit "niedrigerer Ziffer", "logarithmisch klein" oder "es ... bedeutet den schlimmsten Fall von logarithmisch quadratisch" meinen. Könnten Sie das klarstellen?
David Richerby

-1

Für 32-Bit-Intervalle bin ich gerade auf diese O(1)Lösung in Hacker Rank-Editorials gestoßen. Ich habe keine Ahnung, wie es funktioniert, aber es funktioniert. (Vielleicht kann jemand erklären, warum es funktioniert.)

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

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


2
Wie unterscheidet sich deine Antwort (nach der Korrektur) von der von ysb.4 (außerdem hat er erklärt, was los ist)? Was macht 'return b' mit nicht angegebenem 'b'? Tut mir leid, aber ich kann nicht auf den von Ihnen angegebenen Link zugreifen.
Evil
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.