Wir erhalten einen Zufallszahlengenerator, RandNum50
der gleichmäßig eine Zufallszahl im Bereich von 1 bis 50 erzeugt. Wir können nur diesen Zufallszahlengenerator verwenden, um alle Ganzzahlen von 1 bis 100 in zufälliger Reihenfolge zu generieren und zu drucken. Jede Zahl muss genau einmal kommen, und die Wahrscheinlichkeit, dass eine Zahl an einem beliebigen Ort auftritt, muss gleich sein.
Was ist der effizienteste Algorithmus dafür?
algorithms
integers
randomness
random-number-generator
Raj Wadhwa
quelle
quelle
RandNum100 = (RandNum50() * 2) - (RandNum50 > 25) ? 0 : 1)
.Antworten:
Ich dachte (also kann es falsch sein :-) an diese -Lösung, die das Fisher-Yates-Shuffle verwendet . Um bei jeder Iteration eine gleichmäßige Verteilung mit guter Annäherung (siehe Abschnitt BEARBEITEN) zu erhalten, können Sie diesen Trick verwenden, um einen Wert zwischen 0 und k - 1 zu erzeugen :O(N2) 0 k - 1
krand
Der Fisher-Yates-Algorithmus wird:
BEARBEITEN:
Wie von Erick hervorgehoben,m = ⌈ log2( k ) ⌉ r k
krand
liefert die obige Funktion keine wirklich gleichmäßige Verteilung. Es gibt andere Methoden, mit denen eine bessere (willkürlich bessere) und schnellere Annäherung erzielt werden kann. (meines Wissens) besteht die einzige Möglichkeit, eine wirklich gleichmäßige Verteilung zu erhalten, darin, die Ablehnungsstichprobe zu verwenden : Wählen Sie Zufallsbits, und wenn die erhaltene Zahl r kleiner als k ist, geben Sie sie zurück, andernfalls generieren Sie sie eine andere Zufallszahl; eine mögliche Implementierung:quelle
Wie wäre es mit einem Beweis, dass es keinen solchen Algorithmus gibt, der garantiert nur eine begrenzte Anzahl von
RandNum50()
Anrufen erfordert, da andere Leute ungefähre Lösungen und Lösungen angegeben haben, bei denen eine unbestimmte Anzahl von Abweichungen vorgenommen wird ?Wie andere angemerkt haben, entspricht das Drucken der Zahlen von 1 bis 100 in zufälliger Reihenfolge dem Drucken einer zufälligen Permutation dieser Zahlen; es gibt 100! von diesen Permutationen, und daher muss jede bestimmte Permutation mit der Wahrscheinlichkeit ausgegeben werden1100!
RandNum50
RandNum50
RandNum50
quelle
Wenn Sie nicht wissen, wie Sie eine Uniform, wie in diesem Beitrag vorgeschlagen, aus einem zufälligen Bit generieren können, können Sie auf diese Weise auch direkt eine Annäherung der Uniform generieren (was Vor's "Trulyrand" entspricht, aber schneller ist):
quelle
Ich habe die Analyse nicht durchgeführt, um zu bestätigen, wie einheitlich (oder nicht) dies sein würde, und es könnte angepasst werden, um ein echtes Shuffle zu sein, aber könnten Sie einfach aus einem Startarray des
i
th-Index =i + 1
den(k + RandNum50() + RandNum50() - 1) mod (100 - k)
Index mit auswählen Entfernung, fürk
= 0..99?Dies "drückt" den Peak in der
RandNum50() + RandNum50()
Verteilung gleichmäßig nach vorne.Ich bin mir ziemlich sicher, dass dies nicht ganz richtig ist, wie ich es angegeben habe, da der 0-Index (1) nicht von der ersten Wahl erhältlich ist und ich nicht schnell eine alternative 1..50 + 1..50-Anpassung sehen kann, die 0 ergibt ..99.
Aktualisieren
Um das von mir festgestellte Problem zu beheben, habe ich,
RandNum100
wie in den Fragenkommentaren erwähnt, den erstenk
Versatz zufällig initialisiert .Dies erzeugt eine Verteilung mit einer signifikanten Welle an der Vorderseite.
Anstatt um 1 voranzukommen, habe ich einen anderen verwendet,
RandNum50
um diesen zuerst zu erhöhenk
. Dies führt zu einem Ergebnis, das für mich zufällig genug ist, aber immer noch nicht "wirklich" zufällig ist, wie leicht zu erkennen ist, wenn Sie K in 2 ändern.Testen von VB.NET-Code, bei dem ich sogar für K. gesorgt habe. Beachten Sie, dass es sich um O (K), 6K + 2 handelt.
quelle