Ecco un problema che mi ha infastidito per un po '. Supponiamo che una stringa sia una sequenza di 1 e 0 e una stringa di caratteri jolly sia una sequenza di 1, 0 e? S. Tutte le stringhe e le stringhe jolly hanno la stessa lunghezza. Questi sono caratteri jolly UNIX standard; 10 ?? 1 partite 10011, 10111, ecc. A? corrisponde a 1 o 0 in quella posizione. Se e w sono stringhe di caratteri jolly, allora scriviamo v ≤ w se ogni stringa corrispondente a v corrisponde anche a w .
I problemi : data una serie di stringhe di caratteri jolly e una query v (anche una stringa di caratteri jolly), esiste una w ∈ S tale che v ≤ w ? E se no, possiamo aggiungere v a S in modo efficiente?
Ecco la O ovvia ( ksoluzione (dovekè la dimensione delle stringhe,mè la dimensione della parola della RAM (di solito 32 o 64)): esamina ogni elemento dell'elenco e verifica la condizione (che può essere eseguita in 2 o 3 operazioni usando bit-twiddling). Verifica anche sev≥w èvalido per qualsiasi elementowdurante la scansione. Sevfallisce il nostro test, quindi aggiungival set e rimuovi iwche abbiamo contrassegnato.
Ma non è abbastanza veloce. Sarebbe davvero bello se ci fosse una soluzione o, in un mondo perfetto, una complessità simile a un albero radix ( O ( k ) ). Va anche bene che le query siano approssimativamente corrette : vale a dire, se v ≤ w , restituisce yes o no; ma se la condizione non regge sicuramente restituire no.
Sebbene ciò non aiuti la complessità del caso peggiore, puoi supporre che tutti gli elementi in siano delimitati da una stringa jolly; cioè esiste una v tale che per tutto w ∈ S , v ≥ w .
Idee che ho provato
- Le stringhe jolly formano una semilattice di join. Potremmo avere un albero n-ary che contiene stringhe di caratteri jolly; le foglie sarebbero stringhe di caratteri jolly e i rami rappresenterebbero l'unione di tutti i bambini. Se la query e il join sono incomparabili, non dobbiamo perdere tempo cercando di confrontarci con tutti i figli di quel ramo. Inoltre, se eseguiamo un aggiornamento e l'aggiornamento sembra essere maggiore di un join, possiamo semplicemente eliminare l'intero ramo. Sfortunatamente, questo è ancora nel peggiore dei casi, e non sempre troviamo i "migliori" join da effettuare quando si scansiona l'albero per aggiungere elementi.
- Si potrebbe formare un trie radice di . Sappiamo che S è delimitato da una stringa jolly; supponiamo che sia? 0? 0. Quindi tutti i rami del trie devono essere solo sul 1 ° e 3 ° bit delle stringhe. Se il bit corrente su cui stiamo eseguendo la diramazione della query è 1, dobbiamo controllare? e i 1 rami; se è 0, controlliamo il? e i 0 rami; se lo è?, controlliamo solo il? ramo. Poiché dobbiamo potenzialmente prendere più rami, questo non sembra molto buono (è difficile aggiornare il trie per lo stesso motivo). Poiché la corrispondenza è un'operazione molto molto rapida, fa male rispetto alla strategia ingenua fare un sacco di traversata in un albero (seguire un mucchio di puntatori è molto più costoso che fare alcuni OR e AND).
Lavoro correlato
Nella comunità delle reti, questo problema si manifesta come "classificazione dei pacchetti", ecco un buon sondaggio sugli algoritmi e le strutture di dati conosciute . Sfortunatamente, si presume quasi sempre che le stringhe jolly corrispondano solo ai prefissi e che la query sia una tupla di tali stringhe. Ovviamente, possiamo sempre convertire una stringa jolly generale per soddisfare questi criteri: 1? 00? 1 ?? è (1,?, 0, 0,?, 1,?,?). Questo non sarebbe efficace, però. L'altro presupposto è che queste tuple sono associate a un "colore" e che l'interrogazione dovrebbe restituire il colore (non solo che corrisponda). Questo rende il problema molto più difficile, perché dobbiamo ordinare le tuple (oppure è ambiguo quale (0,?) E (?, 1) corrisponda (0, 1)).
Nella comunità degli algoritmi ho trovato molti risultati relativi alla ricerca di sottostringhe che corrispondono a "non importa". Questo è un problema considerevolmente più difficile e non posso davvero usare nessuna delle tecniche.
In conclusione
Grazie per qualsiasi aiuto!