algoritmo per il problema di parità prefisso


8

Il problema di parità prefisso può essere definito come segue. Ti viene data una stringa di lunghezza e inizialmente ogni carattere èSn0. Quindi si desidera creare una struttura di dati in grado di supportare gli aggiornamenti come segue.

  1. Per una data i modificare S[i] per entrambi 0 o 1
  2. per una data i trova la parità di S[1]+S[2]+...+S[i].

Dall'alto della mia testa, c'è una soluzione che può supportare questo tipo di query in O(logn)tempo, pur utilizzando solo lo spazio lineare e il tempo di preelaborazione lineare per costruire la struttura dei dati. L'idea è quella di costruire un albero di ricerca binario completo sopra la stringa in cui le foglie corrispondono ai singoli caratteri diSe in ogni nodo interno memorizziamo la somma di tutti i caratteri che sono foglie nel sottoalbero definito da quel nodo. In questo modo possiamo supportare banalmente entrambi gli aggiornamenti inO(logn) tempo.

Tuttavia, ho trovato un documento che dimostra un limite inferiore per questo problema, affermando che non puoi fare di meglio O(lognloglogn)per gli aggiornamenti, e ho anche trovato il seguente documento http://link.springer.com/chapter/10.1007%2F3-540-51542-9_5 e un collegamento diretto al pdf , che fornisce un algoritmo che raggiunge tale limite, essendo quindi ottimale.

Mi piacerebbe capire questo algoritmo, tuttavia la spiegazione è come 1 pagina e mancano molti dettagli.

Quindi mi chiedevo se ci fosse un'altra fonte su questo problema, perché trovo molto difficile trovarne una o è questa l'unica fonte disponibile?

Grazie in anticipo

Risposte:


9

Ho letto rapidamente il documento che hai collegato. Sulla base delle idee fornite in quel documento, ecco una semplice struttura di dati che ottiene unO(lognloglogn) tempo limitato per ogni operazione.

Hai detto nella tua domanda che puoi usare alberi equilibrati e aumentati per accelerare questo. In particolare, se si dispone di un albero binario e si aumenta ogni nodo con la parità della sottostruttura sinistra, è possibile eseguire aggiornamenti e ricerche in tempoO(logn)ogni. È veloce, ma non abbastanza veloce.

Ora, considera la seguente generalizzazione della tua idea. Supponiamo che invece di utilizzare un albero binario, utilizziamo un albero a più vie con fattore di ramificazionek. Aumentiamo ogni chiave in ciascun nodo con la parità di tutti i sottotitoli che la precedono (questo generalizza l'idea di memorizzare la parità della sottostruttura sinistra). Ora, pensiamo a come faremmo una ricerca o un aggiornamento in questo albero. Per fare una ricerca, usiamo una versione leggermente modificata dell'algoritmo di ricerca dell'albero binario di prima: cammina dalla cima dell'albero verso il basso, ad ogni passo accumulando la parità della sottostruttura puramente alla sinistra di ciascun nodo. L'altezza dell'albero in questo caso saràO(logkn) e lo facciamo O(1) lavorare per nodo, quindi sarà il costo di una ricerca O(logkn).

Tuttavia, con questa configurazione, il costo per eseguire un aggiornamento aumenta. In particolare, se cambiamo la parità di un elemento, dobbiamo camminare dal basso dell'albero verso l'alto, cambiando la parità memorizzata di ogni chiave in ogni nodo sul percorso verso l'alto. Ci sonok chiavi per nodo e O(logkn) nodi sul percorso verso l'alto dalle foglie, quindi sarà il costo di eseguire un'operazione come questa O(klogkn)=O(klogklogn), che è troppo lento. Se potessimo in qualche modo eliminare questo extrak termine, allora saremmo in affari.

L'intuizione del documento è la seguente. Se pensi al nostro problema iniziale, avevamo una serie di dimensionine volevo essere in grado di calcolare le parità dei prefissi. Ora abbiamo unk-albero dove dove, ad ogni nodo, dobbiamo essere in grado di risolvere il problema della parità dei prefissi su matrici di dimensioni kciascuno, poiché ciascun nodo memorizza nella cache informazioni sui livelli sottostanti. Nella struttura di dati di cui sopra, abbiamo risolto il problema della parità dei prefissi in ciascun nodo semplicemente memorizzando un array delle parità dei prefissi, il che significa che se è necessario eseguire un aggiornamento, il costo èO(k). L'intuizione del documento è che utilizzando una struttura di dati più intelligente su ciascun nodo, è possibile eseguire questi aggiornamenti in modo significativamente più efficiente.

In particolare, il documento fornisce le seguenti intuizioni. Supponiamo chekè "piccolo", per alcune definizioni di piccolo che sceglieremo in seguito. Se si desidera risolvere il problema di parità dei prefissi su un array di dimensionik, quindi ci sono solo 2k diverse possibili matrici di bit di lunghezza k. Inoltre, ci sono solok possibili query di ricerca che è possibile effettuare su un array di dimensioni un po ' k. Di conseguenza, il numero di possibili combinazioni di un array e una query èk2k. Se scegliamokper essere abbastanza piccoli, possiamo rendere questa quantità così piccola che diventa possibile pre-calcolare il risultato di ogni possibile array e ogni possibile query. Se lo facciamo, possiamo aggiornare la nostra struttura di dati come segue. In ogni nodo dik-way tree, invece di avere ogni chiave memorizza la parità della sua sottostruttura sinistra, invece memorizziamo una matrice di kbit, uno per ogni chiave nel nodo. Quando vogliamo trovare la parità di tutti i nodi a sinistra diifiglio, facciamo solo una ricerca in una tabella indicizzata da quelli k bit (considerati come numeri interi) e l'indice i. A condizione che possiamo calcolare questa tabella abbastanza velocemente, ciò significa che l'esecuzione di una query di parità con prefisso richiederà ancora tempoO(logkn), ma ora gli aggiornamenti richiedono tempo O(logkn) anche perché sarà il costo di una query di parità prefisso su un dato nodo O(1).

Gli autori dell'articolo hanno notato che se lo scegli k=lgn2, il numero di possibili query che è possibile effettuare è lgn22lgn2=lgn2n=o(n). Inoltre, sarà il costo di eseguire qualsiasi operazione sull'albero risultanteO(logkn)=O(lognloglgn2)=O(lognloglogn). Il trucco è che ora devi fareo(n)precomputazione all'inizio della configurazione della struttura dei dati. Gli autori offrono un modo per ammortizzare questo costo utilizzando una struttura dati diversa per le query iniziali fino a quando non è stato svolto abbastanza lavoro per giustificare l'esecuzione del lavoro necessario per impostare la tabella, sebbene si possa sostenere che è necessario spendereO(n) tempo di costruire l'albero in primo luogo e che ciò non influirà sul tempo di esecuzione complessivo.

Quindi, in sintesi, l'idea è la seguente:

  • Invece di usare un albero binario aumentato, usa un albero aumentato k-albero.
  • Si noti che con piccoli k, tutto possibile k-l'elenco di bit e le query su tali elenchi possono essere pre-calcolati.
  • Utilizzare questa struttura di dati pre-calcolata su ciascun nodo nella struttura.
  • Scegliere k=lgn2 rendere l'altezza dell'albero e, quindi, il costo per operazione, O(lognloglogn).
  • Evitare il costo di precomputazione iniziale utilizzando una struttura di dati di sostituzione temporanea in ciascun nodo fino a quando la precomputazione diventa utile.

Tutto sommato, è una struttura di dati intelligente. Grazie per aver posto questa domanda e averla collegata: ho imparato molto nel processo!

Come addendum, molte delle tecniche che sono entrate in questa struttura di dati sono strategie comuni per accelerare soluzioni apparentemente ottimali. L'idea di precompilare tutte le possibili query su oggetti di piccole dimensioni è spesso chiamata Metodo dei quattro russi e può essere vista in altre strutture di dati come la struttura di dati Fischer-Heun per le query minime di intervallo o l'algoritmo decrementale per la connettività ad albero. Allo stesso modo, la tecnica di utilizzo di alberi multiway bilanciati aumentati con un fattore di ramificazione logaritmica emerge in altri contesti, come la struttura di dati deterministici originale per la connettività dei grafici dinamici, in cui un tale approccio viene utilizzato per accelerare le query di connettività daO(logn) per O(lognloglogn).

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.