Pensé en un enfoque de divide y vencerás que podría funcionar.
Primero, en el preprocesamiento debe insertar todos los números de menos de la mitad de su tamaño de entrada ( n / 3) en una lista.
Dada una cadena: 0000010101000100
(tenga en cuenta que este ejemplo en particular es válido)
Inserte todos los primos (y 1) del 1 al (16/2) en una lista: {1, 2, 3, 4, 5, 6, 7}
Luego divídalo por la mitad:
100000101 01000100
Siga haciendo esto hasta llegar a cadenas de tamaño 1. Para todas las cadenas de tamaño uno con un 1 en ellas, agregue el índice de la cadena a la lista de posibilidades; de lo contrario, devuelve -1 por falla.
También deberá devolver una lista de distancias de separación aún posibles, asociadas con cada índice inicial. (Comience con la lista que hizo arriba y elimine los números a medida que avanza) Aquí, una lista vacía significa que solo está tratando con un 1 y, por lo tanto, cualquier espacio es posible en este punto; de lo contrario, la lista incluye espacios que deben descartarse.
Continuando con el ejemplo anterior:
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
En el primer paso combinado, tenemos ocho conjuntos de dos ahora. En el primero, tenemos la posibilidad de un conjunto, pero aprendemos que el espacio entre 1 es imposible debido a que el otro cero está allí. Entonces devolvemos 0 (para el índice) y {2,3,4,5,7} por el hecho de que el espaciado entre 1 es imposible. En el segundo, no tenemos nada y, por lo tanto, devuelve -1. En el tercero tenemos una coincidencia sin espacios eliminados en el índice 5, así que devuelve 5, {1,2,3,4,5,7}. En el cuarto par devolvemos 7, {1,2,3,4,5,7}. En el quinto, devuelve 9, {1,2,3,4,5,7}. En el sexto, devuelve -1. En el séptimo, devuelve 13, {1,2,3,4,5,7}. En el octavo, devuelve -1.
Combinando nuevamente en cuatro conjuntos de cuatro, tenemos:
1000
: Retorno (0, {4,5,6,7})
0101
: Retorno (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: Retorno (9, {3,4,5,6,7})
0100
: Retorno (13, {3,4,5,6,7})
Combinando en conjuntos de ocho:
10000101
: Retorno (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Retorno (9, {4,7}), (13, {3,4,5,6,7})
Combinando en un conjunto de dieciséis:
10000101 01000100
A medida que avanzamos, seguimos comprobando todas las posibilidades hasta ahora. Hasta este paso, hemos dejado cosas que iban más allá del final de la cadena, pero ahora podemos verificar todas las posibilidades.
Básicamente, verificamos el primer 1 con espacios de 5 y 7, y encontramos que no se alinean con los 1. (Tenga en cuenta que cada verificación es CONSTANTE, no lineal). Luego verificamos la segunda (índice 5) con espacios de 2, 3, 4, 5, 6 y 7, o lo haríamos, pero podemos detenernos en 2 desde eso realmente coincide.
¡Uf! Ese es un algoritmo bastante largo.
No sé 100% si es O (n log n) debido al último paso, pero todo lo que hay hasta allí definitivamente es O (n log n) por lo que puedo decir. Volveré a esto más tarde e intentaré refinar el último paso.
EDITAR: Cambié mi respuesta para reflejar el comentario de Welbog. Lo siento por el error. Escribiré un pseudocódigo más tarde, también, cuando tenga un poco más de tiempo para descifrar lo que escribí nuevamente. ;-)