Das habe ich mir ausgedacht, für das kein zusätzliches Vorzeichenbit erforderlich ist:
for i := 0 to n - 1
while A[A[i]] != A[i]
swap(A[i], A[A[i]])
end while
end for
for i := 0 to n - 1
if A[i] != i then
print A[i]
end if
end for
Die erste Schleife permutiert das Array, sodass sich x
einer dieser Einträge an der Position befindet , wenn das Element mindestens einmal vorhanden ist A[x]
.
Beachten Sie, dass es beim ersten Erröten möglicherweise nicht wie O (n) aussieht, aber es ist - obwohl es eine verschachtelte Schleife hat, läuft es immer noch in der O(N)
Zeit. Ein Swap findet nur statt, wenn es einen i
solchen gibt A[i] != i
, und jeder Swap setzt mindestens ein Element so, dass A[i] == i
, wo das vorher nicht wahr war. Dies bedeutet, dass die Gesamtzahl der Swaps (und damit die Gesamtzahl der Ausführungen des while
Schleifenkörpers) höchstens beträgt N-1
.
Die zweite Schleife gibt die Werte aus, x
für die A[x]
nicht gleich ist. x
Da die erste Schleife garantiert, dass x
eine dieser Instanzen vorhanden ist , wenn sie mindestens einmal im Array vorhanden ist, A[x]
bedeutet dies, dass die Werte gedruckt werden, in x
denen sie nicht vorhanden sind das Array.
(Ideone-Link, damit Sie damit spielen können)
a[a[i]]
, und die O (1) -Raumbeschränkung deuten darauf hin, dass dieswap()
Operation der Schlüssel ist.5
nicht im Bereich liegt0..N-1
(N
in diesem Fall5
).print
Anweisungprint i
in eine Lösung für stackoverflow.com/questions/5249985/… und (vorausgesetzt, die "Tasche" ist ein modifizierbares Array) Qk von stackoverflow.com/questions/3492302/… ist .Die brillante Antwort von caf druckt jede Zahl, die k-mal im Array k-1-mal erscheint. Das ist ein nützliches Verhalten, aber die Frage verlangt wohl, dass jedes Duplikat nur einmal gedruckt wird, und er spielt auf die Möglichkeit an, dies zu tun, ohne die linearen Grenzen von Zeit und konstantem Raum zu überschreiten. Dies kann erreicht werden, indem seine zweite Schleife durch den folgenden Pseudocode ersetzt wird:
Dies nutzt die Eigenschaft aus, dass nach dem Ausführen der ersten Schleife, wenn ein Wert
m
mehr als einmal erscheint, garantiert ist, dass sich eine dieser Erscheinungen an der richtigen Position befindet, nämlichA[m]
. Wenn wir vorsichtig sind, können wir diesen "Heimatort" verwenden, um Informationen darüber zu speichern, ob noch Duplikate gedruckt wurden oder nicht.In der Version von caf wurde beim Durchlaufen des Arrays
A[i] != i
impliziert, dassA[i]
es sich um ein Duplikat handelt. In meiner Version verlasse ich mich auf eine etwas andere Invariante: DiesA[i] != i && A[A[i]] == A[i]
impliziert, dassA[i]
es sich um ein Duplikat handelt , das wir zuvor noch nicht gesehen haben . (Wenn Sie den Teil "den wir noch nicht gesehen haben" löschen, kann der Rest durch die Wahrheit der Invariante des Cafés und die Garantie, dass alle Duplikate eine Kopie an einem Heimatort haben, impliziert werden.) Diese Eigenschaft gilt für Der Anfang (nachdem die erste Runde des Cafés beendet ist) und ich zeigen unten, dass er nach jedem Schritt beibehalten wird.Während wir das Array durchgehen,
A[i] != i
impliziert der Erfolg des Tests, dass esA[i]
sich um ein Duplikat handeln kann, das zuvor noch nicht gesehen wurde. Wenn wir es noch nicht gesehen haben, erwarten wir, dassA[i]
der Heimatort auf sich selbst zeigt - darauf wird in der zweiten Hälfte derif
Erkrankung getestet . Wenn dies der Fall ist, drucken wir es aus und ändern den Heimatort, um auf dieses zuerst gefundene Duplikat zu verweisen. Dadurch wird ein zweistufiger "Zyklus" erstellt.Um zu sehen, dass diese Operation unsere Invariante nicht verändert, nehmen wir an, dass
m = A[i]
eine bestimmte Positioni
zufriedenstellend istA[i] != i && A[A[i]] == A[i]
. Es ist offensichtlich, dass die von uns vorgenommene Änderung (A[A[i]] = i
) dazu beiträgt, zu verhindern, dass andere Ereignisse außerhalb des Hausesm
als Duplikate ausgegeben werden, indem die zweite Hälfte ihrerif
Bedingungen fehlschlägt. Funktioniert sie jedoch, wenn siei
am Heimatort eintrifftm
? Ja, das wird es, denn jetzt, obwohli
wir bei dieser neuen Version feststellen, dass die erste Hälfte derif
BedingungA[i] != i
wahr ist, prüft die zweite Hälfte, ob der Ort, auf den sie zeigt, ein Heimatort ist, und stellt fest, dass dies nicht der Fall ist. In dieser Situation wissen wir nicht mehr, ob der doppelte Wert warm
oderA[m]
war, aber wir wissen das so oder so,Es wurde bereits berichtet , da diese 2 Zyklen garantiert nicht im Ergebnis der ersten Schleife des Cafés erscheinen. (Beachten Sie, dass wennm != A[m]
dann genau eines vonm
undA[m]
mehrmals vorkommt und das andere überhaupt nicht vorkommt.)quelle
Hier ist der Pseudocode
Beispielcode in C ++
quelle
-
mit~
dem Null Problem.O(n)
verborgenen Raum - dien
Vorzeichenbits. Wenn das Array so definiert ist, dass jedes Element nur Werte zwischen0
und enthalten kannn-1
, funktioniert es offensichtlich nicht.Für relativ kleine N können wir div / mod-Operationen verwenden
Nicht C / C ++ aber trotzdem
http://ideone.com/GRZPI
quelle
Nicht wirklich hübsch, aber zumindest sind die Eigenschaften O (N) und O (1) leicht zu erkennen. Grundsätzlich scannen wir das Array und sehen für jede Zahl, ob die entsprechende Position bereits einmal gesehen (N) oder mehrfach gesehen (N + 1) markiert wurde. Wenn es bereits einmal gesehen markiert ist, drucken wir es aus und markieren es bereits mehrfach gesehen. Wenn es nicht markiert ist, markieren wir es bereits einmal und verschieben den ursprünglichen Wert des entsprechenden Index an die aktuelle Position (das Markieren ist eine destruktive Operation).
oder noch besser (schneller, trotz der Doppelschleife):
quelle
if (value > i) a[i--] = a[value];
funktioniert: Wennvalue <= i
wir den Wert dann bereits bei verarbeitet habena[value]
und ihn sicher überschreiben können. Ich würde auch nicht sagen, dass die O (N) -Natur offensichtlich ist! Rechtschreibung: Die Hauptschleife läuftN
mal und wie oft diea[i--] = a[value];
Linie läuft. Diese Zeile kann nur ausgeführt werdena[value] < N
, wenn und jedes Mal unmittelbar danach ein Array-Wert festgelegt wird, der noch nichtN
festgelegt wurdeN
, sodass sie höchstensN
für insgesamt höchstens2N
Schleifeniterationen ausgeführt werden kann.Eine Lösung in C ist:
Es ist O (n) Zeit und O (1) Raumkomplexität.
quelle
Nehmen wir an, wir präsentieren dieses Array als unidirektionale Diagrammdatenstruktur - jede Zahl ist ein Scheitelpunkt und sein Index im Array zeigt auf einen anderen Scheitelpunkt, der eine Kante des Diagramms bildet.
Für noch mehr Einfachheit haben wir Indizes 0 bis n-1 und einen Zahlenbereich von 0..n-1. z.B
0 (3) -> 3 (3) ist ein Zyklus.
Antwort: Durchlaufen Sie einfach das Array anhand von Indizes. Wenn a [x] = a [y] ist, dann ist es ein Zyklus und somit ein Duplikat. Fahren Sie mit dem nächsten Index fort und fahren Sie bis zum Ende eines Arrays fort. Komplexität: O (n) Zeit und O (1) Raum.
quelle
Ein winziger Python-Code zur Demonstration der obigen Methode von caf:
quelle
i
Wert erfolgen muss - beachten Sie dieswhile
in meiner Antwort.Der Algorithmus ist in der folgenden C-Funktion leicht zu erkennen. Abrufen ursprüngliche Arrays, obwohl dies nicht erforderlich ist , möglich sein wird , jede Eingabe modulo unter n .
Ideone Link zum Testen.
quelle
quelle
Ich habe schnell eine Beispielspielplatz-App erstellt, um Duplikate in 0 (n) Zeitkomplexität und konstantem zusätzlichen Platz zu finden. Bitte überprüfen Sie die URL Finding Duplicates
Die oben genannte IMP- Lösung funktionierte, wenn ein Array Elemente von 0 bis n-1 enthält, wobei eine dieser Zahlen beliebig oft vorkommt.
quelle
quelle
Wenn das Array nicht zu groß ist, ist diese Lösung einfacher. Es wird ein weiteres Array mit derselben Größe zum Aktivieren erstellt.
1 Erstellen Sie eine Bitmap / ein Array mit der gleichen Größe wie Ihr Eingabearray
2 Scannen Sie Ihr Eingabearray und erhöhen Sie die Anzahl im obigen Array
3 Scannen Sie nun das Array check_list und drucken Sie das Duplikat entweder einmal oder so oft, wie es dupliziert wurde
Natürlich nimmt es doppelt so viel Platz ein wie die oben angegebene Lösung, aber die Zeiteffizienz beträgt O (2n), was im Grunde genommen O (n) ist.
quelle
O(1)
Platz.