Die Aufgabe besteht eindeutig darin, einen Algorithmus zu finden, der O (1) in der Länge N der erforderlichen Liste von Zahlen ist. Es spielt also keine Rolle, ob Sie die Top-100-Nummer oder die 10000-Nummer benötigen, die Einfügezeit sollte O (1) sein.
Der Trick dabei ist, dass, obwohl diese O (1) -Anforderung für die Listeneinfügung erwähnt wird, die Frage nichts über die Reihenfolge der Suchzeit im gesamten Nummernraum aussagte, aber es stellt sich heraus, dass dies gemacht werden kann. O (1) auch. Die Lösung lautet dann wie folgt:
Ordnen Sie eine Hash-Tabelle mit Zahlen für Schlüssel und Paaren verknüpfter Listenzeiger für Werte an. Jedes Zeigerpaar ist der Anfang und das Ende einer verknüpften Listenfolge. Dies ist normalerweise nur ein Element, dann das nächste. Jedes Element in der verknüpften Liste wird neben dem Element mit der nächsthöheren Nummer angezeigt. Die verknüpfte Liste enthält daher die sortierte Folge der erforderlichen Nummern. Notieren Sie sich die niedrigste Nummer.
Nimm eine neue Zahl x aus dem Zufallsstrom.
Ist es höher als die zuletzt aufgezeichnete niedrigste Zahl? Ja => Schritt 4, Nein => Schritt 2
Schlagen Sie die Hash-Tabelle mit der gerade genommenen Nummer. Gibt es einen Eintrag? Ja => Schritt 5. Nein => Nimm eine neue Zahl x-1 und wiederhole diesen Schritt (dies ist eine einfache lineare Suche nach unten, trage mich hier ein, dies kann verbessert werden und ich werde erklären, wie)
Fügen Sie mit dem soeben aus der Hash-Tabelle erhaltenen Listenelement die neue Nummer direkt nach dem Element in die verknüpfte Liste ein (und aktualisieren Sie den Hash).
Nimm die niedrigste Nummer, die ich aufgezeichnet habe (und entferne sie aus dem Hash / der Liste).
Schlagen Sie die Hash-Tabelle mit der gerade genommenen Nummer. Gibt es einen Eintrag? Ja => Schritt 8. Nein => Nimm eine neue Zahl l + 1 und wiederhole diesen Schritt (dies ist eine einfache lineare Suche nach oben)
Bei einem positiven Treffer wird die Zahl zur neuen niedrigsten Zahl. Weiter zu Schritt 2
Um doppelte Werte zuzulassen, muss der Hash den Anfang und das Ende der verknüpften Listensequenz von Elementen, die doppelte Werte sind, beibehalten. Durch Hinzufügen oder Entfernen eines Elements zu einer bestimmten Taste wird der angezeigte Bereich vergrößert oder verkleinert.
Der Einsatz hier ist O (1). Die genannten Suchanfragen sind, denke ich, O (durchschnittlicher Unterschied zwischen Zahlen). Die durchschnittliche Differenz erhöht sich mit der Größe des Nummernraums, verringert sich jedoch mit der erforderlichen Länge der Nummernliste.
Die lineare Suchstrategie ist also ziemlich schlecht, wenn der Nummernraum groß ist (z. B. für einen 4-Byte-Int-Typ, 0 bis 2 ^ 32-1) und N = 100. Um dieses Leistungsproblem zu umgehen, können Sie parallele Sätze von Hashtabellen aufbewahren, bei denen die Zahlen auf höhere Beträge (z. B. 1s, 10s, 100s, 1000s) gerundet werden, um geeignete Schlüssel zu erstellen. Auf diese Weise können Sie einen höheren oder niedrigeren Gang einlegen, um die erforderlichen Suchvorgänge schneller durchzuführen. Die Leistung wird dann zu einem O (log numberrange), was meiner Meinung nach konstant ist, also auch zu O (1).
Stellen Sie sich zur Verdeutlichung vor, Sie hätten die Nummer 197 zur Hand. Wenn Sie den 10er-Hash-Tisch treffen, wird er mit '190' auf die nächste Zehn gerundet. Etwas? Nein. Also gehen Sie in 10s runter, bis Sie sagen 120 drücken. Dann können Sie bei 129 in der 1s-Hash-Tabelle beginnen und 128, 127 versuchen, bis Sie etwas treffen. Sie haben nun in der verknüpften Liste die Stelle gefunden, an der die Nummer 197 eingefügt werden soll. Während Sie sie eingeben, müssen Sie auch die 1s-Hashtabelle mit dem Eintrag 197, die 10s-Hashtabelle mit der Nummer 190, die 100s mit 100 usw. aktualisieren. Die meisten Schritte Sie müssen hier immer das 10-fache des Protokolls des Nummernkreises machen.
Ich könnte einige der Details falsch verstanden haben, aber da dies der Programmiereraustausch ist und der Kontext Interviews war, würde ich hoffen, dass die obige Antwort überzeugend genug für diese Situation ist.
BEARBEITEN Ich habe hier einige zusätzliche Details hinzugefügt, um das Schema der parallelen Hashtabelle zu erläutern und um zu erläutern, wie die von mir erwähnten schlechten linearen Suchen durch eine O (1) -Suche ersetzt werden können. Ich habe auch festgestellt, dass es nicht notwendig ist, nach der nächstniedrigeren Nummer zu suchen, da Sie direkt dorthin gelangen können, indem Sie in die Hash-Tabelle mit der niedrigsten Nummer schauen und zum nächsten Element übergehen.