J'ai pensé à une approche de division et de conquête qui pourrait fonctionner.
Tout d'abord, lors du prétraitement, vous devez insérer tous les nombres inférieurs à la moitié de votre taille d'entrée ( n / 3) dans une liste.
Étant donné une chaîne: 0000010101000100
(notez que cet exemple particulier est valide)
Insérez tous les nombres premiers (et 1) de 1 à (16/2) dans une liste: {1, 2, 3, 4, 5, 6, 7}
Puis divisez-le en deux:
100000101 01000100
Continuez à faire cela jusqu'à ce que vous arriviez à des chaînes de taille 1. Pour toutes les chaînes de taille un avec un 1, ajoutez l'index de la chaîne à la liste des possibilités; sinon, retournez -1 en cas d'échec.
Vous devrez également renvoyer une liste des distances d'espacement encore possibles, associées à chaque index de départ. (Commencez par la liste que vous avez faite ci-dessus et supprimez les nombres au fur et à mesure) Ici, une liste vide signifie que vous n'avez affaire qu'à un 1 et que tout espacement est donc possible à ce stade; sinon, la liste comprend des espacements qui doivent être exclus.
Continuez donc avec l'exemple ci-dessus:
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
Dans la première étape de combinaison, nous avons maintenant huit séries de deux. Dans le premier, on a la possibilité d'un ensemble, mais on apprend que l'espacement de 1 est impossible à cause de la présence de l'autre zéro. Nous retournons donc 0 (pour l'index) et {2,3,4,5,7} pour le fait que l'espacement de 1 est impossible. Dans le second, nous n'avons rien et retournons donc -1. Dans le troisième, nous avons une correspondance sans espacement éliminé dans l'index 5, donc renvoyez 5, {1,2,3,4,5,7}. Dans la quatrième paire, nous retournons 7, {1,2,3,4,5,7}. Dans le cinquième, renvoyez 9, {1,2,3,4,5,7}. Dans le sixième, retournez -1. Dans le septième, retournez 13, {1,2,3,4,5,7}. Au huitième, retournez -1.
En combinant à nouveau en quatre séries de quatre, nous avons:
1000
: Retour (0, {4,5,6,7})
0101
: Retour (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: Retour (9, {3,4,5,6,7})
0100
: Retour (13, {3,4,5,6,7})
Combinaison en ensembles de huit:
10000101
: Retour (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Retour (9, {4,7}), (13, {3,4,5,6,7})
Combinant en un ensemble de seize:
10000101 01000100
Au fur et à mesure que nous progressons, nous continuons à vérifier toutes les possibilités jusqu'à présent. Jusqu'à cette étape, nous avons laissé des éléments qui dépassaient la fin de la chaîne, mais nous pouvons maintenant vérifier toutes les possibilités.
Fondamentalement, nous vérifions le premier 1 avec des espacements de 5 et 7, et constatons qu'ils ne s'alignent pas sur les 1. (Notez que chaque vérification est CONSTANTE et non linéaire) Ensuite, nous vérifions la seconde (index 5) avec des espacements de 2, 3, 4, 5, 6 et 7 - ou nous le ferions, mais nous pouvons nous arrêter à 2 puisque qui correspond en fait.
Phew! C'est un algorithme assez long.
Je ne sais pas à 100% si c'est O (n log n) à cause de la dernière étape, mais tout jusqu'à là est définitivement O (n log n) pour autant que je sache. J'y reviendrai plus tard et j'essaierai d'affiner la dernière étape.
EDIT: J'ai changé ma réponse pour refléter le commentaire de Welbog. Désolé pour l'erreur. J'écrirai aussi un pseudocode plus tard, quand j'aurai un peu plus de temps pour déchiffrer ce que j'ai écrit à nouveau. ;-)