Pensei em uma abordagem de dividir e conquistar que poderia funcionar.
Primeiro, no pré-processamento, você precisa inserir todos os números com menos da metade do seu tamanho de entrada ( n / 3) em uma lista.
Dada uma sequência: 0000010101000100
(observe que este exemplo em particular é válido)
Insira todos os números primos (e 1) de 1 a (16/2) em uma lista: {1, 2, 3, 4, 5, 6, 7}
Depois divida ao meio:
100000101 01000100
Continue fazendo isso até chegar às cadeias de tamanho 1. Para todas as cadeias de tamanho um com um 1, adicione o índice da cadeia à lista de possibilidades; caso contrário, retorne -1 para falha.
Você também precisará retornar uma lista de distâncias de espaçamento ainda possíveis, associadas a cada índice inicial. (Comece com a lista que você criou acima e remova os números à medida que avança) Aqui, uma lista vazia significa que você está lidando apenas com 1 e, portanto, qualquer espaçamento é possível neste momento; caso contrário, a lista inclui espaçamentos que devem ser descartados.
Então, continuando com o exemplo acima:
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
No primeiro passo da combinação, temos oito conjuntos de dois agora. No primeiro, temos a possibilidade de um conjunto, mas aprendemos que o espaçamento de 1 é impossível por causa do outro zero estar lá. Portanto, retornamos 0 (para o índice) e {2,3,4,5,7} pelo fato de que o espaçamento por 1 é impossível. No segundo, não temos nada e, portanto, retornamos -1. No terceiro, temos uma partida sem espaçamento eliminada no índice 5, então retorne 5, {1,2,3,4,5,7}. No quarto par, retornamos 7 {1,2,3,4,5,7}. No quinto, retorne 9 {1,2,3,4,5,7}. No sexto, retorne -1. No sétimo, retorne 13, {1,2,3,4,5,7}. No oitavo, retorne -1.
Combinando novamente em quatro conjuntos de quatro, temos:
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 em conjuntos de oito:
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 um conjunto de dezesseis:
10000101 01000100
À medida que progredimos, continuamos verificando todas as possibilidades até o momento. Até essa etapa, deixamos coisas que iam além do final da string, mas agora podemos verificar todas as possibilidades.
Basicamente, verificamos o primeiro 1 com espaçamento de 5 e 7 e descobrimos que eles não estão alinhados com o número 1. (Observe que cada verificação é CONSTANTE, e não o tempo linear). Depois, verificamos a segunda (índice 5) com espaçamentos de 2, 3, 4, 5, 6 e 7 - ou o faria, mas podemos parar em 2 desde que realmente combina.
Ufa! Esse é um algoritmo bastante longo.
Eu não sei 100% se é O (n log n) por causa da última etapa, mas tudo até lá é definitivamente O (n log n) , tanto quanto eu posso dizer. Voltarei a isso mais tarde e tentarei refinar o último passo.
EDIT: Alterei minha resposta para refletir o comentário de Welbog. Desculpe pelo erro. Também escreverei algum pseudocódigo mais tarde, quando tiver um pouco mais de tempo para decifrar o que escrevi novamente. ;-)