Ho pensato a un approccio di divisione e conquista che potesse funzionare.
Innanzitutto, nella preelaborazione è necessario inserire tutti i numeri meno della metà della dimensione di input ( n / 3) in un elenco.
Dato una stringa: 0000010101000100
(nota che questo esempio particolare è valido)
Inserisci tutti i numeri primi (e 1) da 1 a (16/2) in un elenco: {1, 2, 3, 4, 5, 6, 7}
Quindi dividerlo a metà:
100000101 01000100
Continuare a farlo fino a quando non si arriva a stringhe di dimensione 1. Per tutte le stringhe di dimensione 1 con un 1 in esse, aggiungere l'indice della stringa all'elenco di possibilità; in caso contrario, restituire -1 per errore.
Dovrai anche restituire un elenco di distanze di spaziatura ancora possibili, associate a ciascun indice iniziale. (Inizia con l'elenco che hai creato sopra e rimuovi i numeri mentre vai). Qui, un elenco vuoto significa che hai a che fare solo con 1 e quindi a questo punto è possibile qualsiasi spaziatura; in caso contrario l'elenco include spaziature che devono essere escluse.
Quindi continuando con l'esempio sopra:
1000 0101 0100 0100
10 00 01 01 01 00 01 00
1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0
Nella prima fase della combinazione, ora abbiamo otto serie da due. Nel primo, abbiamo la possibilità di un set, ma apprendiamo che la spaziatura di 1 è impossibile a causa dell'altro zero presente. Quindi restituiamo 0 (per l'indice) e {2,3,4,5,7} per il fatto che la spaziatura di 1 è impossibile. Nel secondo, non abbiamo nulla e quindi restituiamo -1. Nel terzo abbiamo una partita senza spaziature eliminate nell'indice 5, quindi restituiamo 5, {1,2,3,4,5,7}. Nella quarta coppia restituiamo 7, {1,2,3,4,5,7}. Nel quinto, restituisce 9, {1,2,3,4,5,7}. Nel sesto, ritorna -1. Nel settimo, ritorno 13, {1,2,3,4,5,7}. Nell'ottavo, ritorna -1.
Combinando nuovamente in quattro serie da quattro, abbiamo:
1000
: Return (0, {4,5,6,7})
0101
: Return (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: Return (9, {3,4,5,6,7})
0100
: Return (13, {3,4,5,6,7})
Combinando in serie di otto:
10000101
: Return (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Return (9, {4,7}), (13, {3,4,5,6,7})
Combinando in un set di sedici:
10000101 01000100
Mentre procediamo, continuiamo a verificare tutte le possibilità finora. Fino a questo passaggio abbiamo lasciato cose che sono andate oltre la fine della stringa, ma ora possiamo verificare tutte le possibilità.
Fondamentalmente, controlliamo il primo 1 con spaziature di 5 e 7 e scopriamo che non si allineano a 1. (Nota che ogni controllo è COSTANTE, non tempo lineare) Quindi controlliamo il secondo (indice 5) con spaziature di 2, 3, 4, 5, 6 e 7-- o vorremmo, ma possiamo fermarci a 2 poiché che corrisponde davvero.
Accidenti! È un algoritmo piuttosto lungo.
Non so al 100% se è O (n log n) a causa dell'ultimo passaggio, ma tutto quello che c'è è sicuramente O (n log n) per quanto ne so. Tornerò su questo più tardi e proverò a perfezionare l'ultimo passaggio.
EDIT: ho cambiato la mia risposta per riflettere il commento di Welbog. Ci scusiamo per l'errore. Scriverò anche qualche pseudocodice, quando avrò un po 'più di tempo per decifrare ciò che ho scritto di nuovo. ;-)