Bisherige 65-Byte-Lösung:
r->{for(int a,b=0,z,i=0;;b=a)if((a=b|1<<(z=r[i++]))==b)return z;}
Neue Lösung. Für sind 19 Bytes enthaltenimport java.math.*;
-8 Bytes dank @Nevay
r->{int z,i=0;for(BigInteger c=BigInteger.ZERO;c.min(c=c.setBit(z=r[i++]))!=c;);return z;}
Probieren Sie es online!
Bearbeiten
Der Algorithmus in meinem ursprünglichen Programm war in Ordnung, aber die statische Größe des verwendeten Datentyps bedeutete, dass er ziemlich schnell kaputt ging, sobald die Größe einen bestimmten Schwellenwert überschritt.
Ich habe den in der Berechnung verwendeten Datentyp geändert, um das Speicherlimit des Programms zu erhöhen, um dies zu berücksichtigen (mit BigInteger
willkürlicher Genauigkeit anstelle von int
oder long
). Dies macht es jedoch fraglich, ob dies gilt oder nichtO(1)
Raumkomplexität .
Ich werde meine Erklärung im Folgenden intakt lassen, aber ich möchte hinzufügen, dass ich jetzt glaube, dass es unmöglich ist, dies zu erreichen O(1)
Raumkomplexität , ohne einige Annahmen zu .
Beweis
Definieren Sie N
als Ganzzahl, so dass2 <= N
.
Sei S
eine Liste, die eine Reihe zufälliger Ganzzahlen darstellt [x{1}, ..., x{N}]
, für x{i}
die die Einschränkung gilt1 <= x{i} <= N
.
Die Zeitkomplexität (in Big-O-Notation), die erforderlich ist, um diese Liste genau einmal pro Element zu durchlaufen, beträgt O(n)
Die Herausforderung besteht darin, den ersten doppelten Wert in der Liste zu finden. Insbesondere suchen wir nach dem ersten Wert S
, der ein Duplikat eines vorherigen Elements in der Liste ist.
Lassen Sie p
und q
die Positionen von zwei Elementen in der Liste sein, so dass p < q
und x{p} == x{q}
. Unsere Herausforderung besteht darin, die kleinste zu finden q
, die diese Bedingungen erfüllt.
Der offensichtliche Ansatz für dieses Problem besteht darin, S zu durchlaufen und zu prüfen, ob unsere x{i}
in einer anderen Liste vorhanden ist T
: Wenn x{i}
sie nicht in vorhanden ist T
, speichern wir sie in T
. Wenn x{i}
in vorhanden ist T
, ist dies der erste doppelte Wert und daher der kleinste q
, und wir geben ihn als solchen zurück. Diese Raumeffizienz istO(n)
.
Um O(1)
Raumkomplexität bei gleichzeitiger Aufrechterhaltung der O(n)
Zeitkomplexität zu erreichen, müssen wir eindeutige Informationen zu jedem Objekt in der Liste auf einer begrenzten Fläche speichern. Aus diesem Grund ist dies die einzige Möglichkeit, mit der ein Algorithmus ausgeführt werden kannO(1)
Die Raumkomplexität ist, wenn: 1. N eine Obergrenze gegeben wird, die dem Speicher entspricht, der zum Speichern der maximalen Anzahl möglicher Werte für einen bestimmten endlichen Datentyp erforderlich ist. 2. Die Neuzuweisung einer einzelnen unveränderlichen Variablen wird nicht auf die Komplexität angerechnet, sondern nur auf die Anzahl der Variablen (eine Liste mit mehreren Variablen). 3. (Basierend auf anderen Antworten) Die Liste ist (oder zumindest die Elemente der Liste sind) veränderbar, und der Datentyp der Liste ist als vorzeichenbehaftete Ganzzahl voreingestellt, sodass Änderungen an Elementen in der Liste vorgenommen werden können ohne zusätzlichen Speicher zu verwenden.
1 und 3 erfordern Annahmen und Spezifikationen zum Datentyp, während 2 erfordert, dass nur die Anzahl der Variablen für die Berechnung der Raumkomplexität berücksichtigt wird und nicht die Größe dieser Variablen. Wenn keine dieser Annahmen akzeptiert wird, ist es unmöglich, sowohl O(n)
Zeitkomplexität als auch O(1)
Raumkomplexität zu erreichen.
Erläuterung
Was für ein Junge, dieser brauchte eine peinlich lange Zeit, um sich ein bisschen Gehirnleistung auszudenken .
Es ist also schwierig, den Bonus zu bekommen. Wir müssen beide die gesamte Liste genau einmal durcharbeiten und verfolgen, welche Werte wir bereits durchlaufen haben, ohne dass zusätzliche Platzkomplexität erforderlich ist .
Bit-Manipulation löst diese Probleme. Wir initialisieren unseren O(1)
'Speicher', ein Paar Ganzzahlen, durchlaufen dann die Liste, indem wir das i-te Bit in unserer ersten Ganzzahl ODER-ODER-verknüpfen und dieses Ergebnis in der zweiten speichern.
Wenn wir zum Beispiel haben 1101
und eine ODER-Operation mit ausführen 10
, erhalten wir 1111
. Wenn wir einen anderen OP machen 10
, haben wir noch 1101
.
Ergo, sobald wir die OP-Operation ausgeführt haben und dieselbe Nummer haben, haben wir unser Duplikat gefunden. Keine Duplikate im Array führen dazu, dass das Programm überläuft und eine Ausnahme auslöst.