Come si possono produrre in modo efficiente tutte le sequenze binarie con un numero uguale di 0 e 1?


10

Una sequenza binaria di lunghezza è solo una sequenza ordinata modo che ogni sia o . Per generare tutte queste sequenze binarie, si può usare l'ovvia struttura ad albero binario nel modo seguente: la radice è "vuota", ma ogni figlio sinistro corrisponde all'aggiunta di alla stringa esistente e ogni figlio destro a un . Ora, ogni sequenza binaria è semplicemente un percorso di lunghezza inizia dalla radice e termina in corrispondenza di una foglia.nx1,,xnxj0101n+1

Ecco la mia domanda:

Possiamo fare di meglio se vogliamo solo generare tutte le stringhe binarie di lunghezza che abbiano esattamente zeri e ?2nnn

Con "possiamo fare di meglio", voglio dire che dovremmo avere una complessità inferiore all'algoritmo sciocco che prima costruisce l'intero albero sopra e poi cerca di trovare quei percorsi con un uguale numero di bordi "sinistro" e "destro".


Riesci a trovare un modo per generare in modo efficiente tutte le sequenze strettamente crescenti di numeri nell'intervallo da 1 a ? 2 nn2n
Marchio Cornelius,

Non posso commentare la complessità, ma il mio ingenuo algoritmo genererebbe le passeggiate lungo i bordi di una griglia quadrata da un angolo a uno diagonale, usando una sorta di schema di backtrack. Ciò significa che 01 e 10 finiscono nella stessa posizione (a differenza del tuo albero) ma con backtrack conosciamo questa storia.
Hendrik Jan

Su una nota forse diversa, ecco un'implementazione Java di un -iteratore . (nk)
Pål GD,

Risposte:


6

Ovviamente ci sono stringhe binarie di lunghezza . Per attraversare il binario un algoritmo deve visitare ogni nodo una volta, ovvero deve fare passaggi.4n2n

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

Consideriamo un algoritmo ricorsivo che attraversa l'albero che hai descritto, ma conta il numero di uno e zeri lungo il suo cammino, cioè attraverserà solo la parte buona dell'albero.
Ma quante stringhe binarie con 0 e 1 ci sono? Scegliamo 1 per le nostre stringhe di lunghezza e usiamo la formula di Stirling nel passaggio 2: nnn2n

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

MODIFICA
Grazie ai commenti di Peter Shor possiamo anche analizzare il numero di passaggi necessari per il secondo algoritmo, che conta gli 1 e gli 0. Sto citando il suo commento dal basso:

Vogliamo trovare tutte le sequenze binarie con esattamente 0 e 1. Attraversiamo l'albero binario in cui ogni nodo è una sequenza al massimo di 0 e 1. Non è necessario visitare alcun nodo con più di 0 o più di 1. quanti nodi dobbiamo visitare? Esistono stringhe con 0 e 1. Sommando tutto su dà . Ora, dobbiamo visitare ciascuno di questi nodi a un costo medio costante per nodo. Possiamo farlo visitando prima ogni bambino sinistro e poi ogni bambino destro.nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1

Usando di nuovo la formula di Stirling otteniamo come tempo di esecuzione del nuovo algoritmo.

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

Devi stare un po 'più attento. Presumibilmente dopo aver generato ogni stringa, la elaboriamo in time. Quindi l'elaborazione di tutte le stringhe bilanciate richiede tempo . Se l'algoritmo di generazione "sciocco" ottimizzato è davvero , allora non c'è molto da guadagnare passando a un algoritmo più intelligente, oltre alle opportunità di bug. Ω(n)Ω(4nn)O(4n)
Yuval Filmus,

@Yuval Filmus: Cosa intendi esattamente per "elaborazione delle stringhe"? Se intendi il tempo impiegato nell'output, che è sicuramente , allora devi considerare quel fattore anche nel tempo di esecuzione dell'algoritmo "sciocco", che quindi è . Θ(n)O(4nn)
tranisstor,

2
Il mio punto era che se ti preoccupi della differenza tra e , allora come minimo devi indicare i tempi di esecuzione corretti; non è sufficiente per rivelare alcuna potenziale differenza tra i due algoritmi. Inoltre, devi stare attento ad analizzare il tuo nuovo algoritmo proposto, per vedere che questi piccoli fattori "trascurabili" non lo rendono più lento dell'algoritmo banale. 4n4n/nO~(4n)
Yuval Filmus,

2
Come si fa a costruire solo la "parte buona" dell'albero senza includere anche le "parti cattive"? È necessario includere tutti i nodi dell'albero che non hanno più di figli a sinistra o figli a destra sul percorso dalla radice a loro. Funziona, ma è necessario un argomento aggiuntivo per dimostrare che funziona. In particolare, è necessario utilizzare la formula . nni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor,

2
Vogliamo trovare tutte le sequenze binarie con esattamente 0 e 1. Attraversiamo l'albero binario in cui ogni nodo è una sequenza al massimo di 0 e 1. Non è necessario visitare alcun nodo con più di 0 o più di 1. quanti nodi dobbiamo visitare? Ci sono stringhe con 0 e 1. Sommando questo su tutti dà . Ora, dobbiamo visitare ciascuno di questi nodi a un costo medio costante per nodo. Possiamo farlo visitando prima ogni bambino sinistro e poi ogni bambino destro.nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor,

2

Forse sto diventando spessa, ma la domanda originale chiedeva un modo per generare tutte le sequenze binarie "bilanciate" di lunghezza 2n che fosse più efficiente che attraversare un albero di tutte le sequenze binarie di lunghezza 2n e produrre solo quelle che erano bilanciate. Quindi perché usare un albero?

Ecco lo pseudocodice per un algoritmo ricorsivo che genera tutte queste sequenze (la parola chiave "rendimento" invia una sequenza all'output):

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;
};

Se sto fraintendendo qualcosa, per favore dimmelo, ma mi sembra che si tratti della risposta più efficiente al problema effettivamente posto, che non ha mai specificato l'uso di un albero.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.