Wie erzeugt man effizient alle Binärsequenzen mit einer gleichen Anzahl von Nullen und Einsen?


10

Eine binäre Folge der Länge n ist nur eine geordnete Folge x1,,xn so dass jedes xj entweder 0 oder 1 . Um alle diese Binärsequenzen zu erzeugen, kann man die offensichtliche Binärbaumstruktur folgendermaßen verwenden: Die Wurzel ist "leer", aber jedes linke Kind entspricht der Addition von 0 zu der vorhandenen Zeichenfolge und jedes rechte Kind zu einer 1 . Nun ist jede binäre Sequenz einfach ein Pfad der Länge n+1 , der an der Wurzel beginnt und an einem Blatt endet.

Hier ist meine Frage:

Können wir es besser machen, wenn wir nur alle Binärzeichenfolgen der Länge erzeugen wollen, 2ndie genau n Nullen und n Einsen haben?

Mit "können wir es besser machen" meine ich, wir sollten eine geringere Komplexität haben als der alberne Algorithmus, der zuerst den gesamten Baum darüber erstellt und dann versucht, diese Pfade mit einer gleichen Anzahl von "linken" und "rechten" Kanten zu finden.


Können Sie einen Weg finden, alle streng ansteigenden Folgen von Zahlen im Bereich von 1 bis 2 n effizient zu erzeugen ? n2n
Cornelius Brand

Ich kann die Komplexität nicht kommentieren, aber mein naiver Algorithmus würde die Spaziergänge entlang der Kanten eines quadratischen Gitters von einer Ecke zu einer diagonalen mithilfe eines Backtrack-Schemas erzeugen. Das bedeutet, dass 01 und 10 an derselben Position landen (im Gegensatz zu Ihrem Baum), aber mit Backtrack kennen wir diese Geschichte.
Hendrik

In einem möglicherweise anderen Sinne ist hier eine Java-Implementierung eines -iterators . (nk)
Pål GD

Antworten:


6

Offensichtlich gibt es Binärzeichenfolgen der Länge . Um die Binärdatei zu durchlaufen, muss ein Algorithmus jeden Knoten einmal besuchen, dh er muss Schritte.4n2n

i=02n2i=22n+11=O(4n)

Betrachten wir einen rekursiven Algorithmus, der den von Ihnen beschriebenen Baum durchläuft, aber die Anzahl der Einsen und Nullen auf seinem Weg zählt, dh nur den guten Teil des Baums durchläuft.
Aber wie viele solcher Binärzeichenfolgen mit 0 und 1 gibt es? Wir wählen 1 für unsere Strings der Länge und verwenden die Stirlingsche Formel in Schritt 2: nnn2n

(2nn)=(2n)!(n!)2=4nπn(1+O(1/n))

BEARBEITEN
Dank der Kommentare von Peter Shor können wir auch die Anzahl der Schritte analysieren, die der zweite Algorithmus benötigt, der die Einsen und Nullen zählt. Ich zitiere seinen Kommentar von unten:

Wir wollen alle Binärsequenzen mit genau 0 und 1 finden. Wir durchlaufen den Binärbaum, wobei jeder Knoten eine Folge von höchstens Nullen und Einsen ist. Wir müssen keinen Knoten mit mehr als 0 oder mehr als 1 besuchen . Wie viele Knoten müssen wir besuchen? Es gibt Strings mit 0 und 1. Wenn man dies über alles ergibt . Jetzt müssen wir jeden dieser Knoten zu konstanten Durchschnittskosten pro Knoten besuchen. Wir können dies tun, indem wir zuerst jedes linke Kind und dann jedes rechte Kind besuchen.nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1

Unter erneuter Verwendung der Stirlingschen Formel erhalten wir als Laufzeit des neuen Algorithmus.

(2n+2n+1)1=4n+11n+1(1+O(1/n))1=O(4nn)

Du musst etwas vorsichtiger sein. Vermutlich verarbeiten wir jeden String nach dem Generieren in -Zeit. Das Verarbeiten aller ausgeglichenen Zeichenfolgen benötigt also Zeit . Wenn der optimierte "alberne" Generierungsalgorithmus tatsächlich , kann durch die Umstellung auf einen intelligenteren Algorithmus nicht viel gewonnen werden, außer Möglichkeiten für Fehler. Ω(n)Ω(4nn)O(4n)
Yuval Filmus

@ Yuval Filmus: Was genau meinst du mit "String-Verarbeitung"? Wenn Sie die für die Ausgabe aufgewendete Zeit meinen, die sicherlich , müssen Sie diesen Faktor auch in der Laufzeit des "dummen" Algorithmus berücksichtigen, der dann . Θ(n)O(4nn)
Tranisstor

2
Mein Punkt war, dass Sie, wenn Sie sich mit dem Unterschied zwischen und befassen , mindestens die richtigen Laufzeiten angeben müssen; reicht nicht aus, um einen möglichen Unterschied zwischen den beiden Algorithmen aufzudecken. Darüber hinaus müssen Sie Ihren vorgeschlagenen neuen Algorithmus sorgfältig analysieren, um festzustellen, dass diese "vernachlässigbaren" kleinen Faktoren ihn nicht langsamer machen als den trivialen Algorithmus. 4n4n/nO~(4n)
Yuval Filmus

2
Wie baut man nur den "guten Teil" des Baumes, ohne auch die "schlechten Teile" einbeziehen zu müssen? Sie müssen alle Knoten des Baums einschließen, die nicht mehr als linke oder rechte Kinder auf dem Pfad von der Wurzel zu ihnen haben. Dies funktioniert, aber Sie benötigen ein zusätzliches Argument, um zu zeigen, dass es funktioniert. Insbesondere müssen Sie die Formel . nni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor

2
Wir wollen alle Binärsequenzen mit genau 0 und 1 finden. Wir durchlaufen den Binärbaum, wobei jeder Knoten eine Folge von höchstens Nullen und Einsen ist. Wir müssen keinen Knoten mit mehr als 0 oder mehr als 1 besuchen . Wie viele Knoten müssen wir besuchen? Es gibt Strings mit 0 und 1. Wenn man dies über alles ergibt . Jetzt müssen wir jeden dieser Knoten zu konstanten Durchschnittskosten pro Knoten besuchen. Wir können dies tun, indem wir zuerst jedes linke Kind und dann jedes rechte Kind besuchen.nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor

2

Vielleicht bin ich dick, aber die ursprüngliche Frage fragte nach einer Möglichkeit, alle "ausgeglichenen" Binärsequenzen der Länge 2n zu erzeugen, die effizienter war, als einen Baum aller Binärsequenzen der Länge 2n zu durchlaufen und nur diejenigen auszugeben, die ausgeglichen waren. Warum also überhaupt einen Baum benutzen?

Hier ist der Pseudocode für einen rekursiven Algorithmus, der alle diese Sequenzen generiert (das Schlüsselwort "Ausbeute" sendet eine Sequenz an die Ausgabe):

function all-balanced(n) {
  all-specified( "", n, n );
};

function all-specified( currentString, zeroes, ones ) {

  if (zeroes == 0) {
    for i = 0 to ones {
      currentString += "1";
    };
    yield currentString;
    return;
  };

  if (ones == 0) {
    for i = 0 to zeroes {
      currentString += "0";
    };
    yield currentString;
    return;
  };

  all-specified( currentString+"0", zeroes-1, ones );
  all-specified( currentString+"1", zeroes, ones-1 );
  return;
};

Wenn ich etwas falsch verstehe, sagen Sie es mir bitte, aber es scheint mir, dass dies die effizienteste Antwort auf das tatsächlich gestellte Problem ist, bei dem die Verwendung eines Baumes nie angegeben wurde.

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.