Pomyślałem o podejściu dziel i rządź, które mogłoby się sprawdzić.
Po pierwsze, w przetwarzaniu wstępnym musisz wstawić wszystkie liczby mniejsze niż połowa rozmiaru wejściowego ( n / 3) do listy.
Biorąc pod uwagę ciąg: 0000010101000100
(zwróć uwagę, że ten konkretny przykład jest prawidłowy)
Wstaw wszystkie liczby pierwsze (i 1) od 1 do (16/2) do listy: {1, 2, 3, 4, 5, 6, 7}
Następnie podziel go na pół:
100000101 01000100
Rób to, aż dojdziesz do łańcuchów o rozmiarze 1. Dla wszystkich łańcuchów o rozmiarze jeden, które zawierają 1, dodaj indeks ciągu do listy możliwości; w przeciwnym razie zwraca -1 w przypadku niepowodzenia.
Musisz także zwrócić listę wciąż możliwych odległości odstępów, powiązanych z każdym indeksem początkowym. (Zacznij od listy, którą utworzyłeś powyżej i usuwaj liczby na bieżąco) W tym przypadku pusta lista oznacza, że masz do czynienia tylko z jedną 1, więc w tym momencie możliwe są dowolne odstępy; w przeciwnym razie lista zawiera odstępy, które należy wykluczyć.
Kontynuując powyższy przykład:
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
W pierwszym etapie łączenia mamy teraz osiem zestawów po dwa. W pierwszym mamy możliwość zbioru, ale dowiadujemy się, że odstęp o 1 jest niemożliwy, ponieważ jest tam drugie zero. Więc zwracamy 0 (dla indeksu) i {2,3,4,5,7} dla faktu, że odstępy o 1 są niemożliwe. W drugim nie mamy nic, więc zwracamy -1. W trzecim mamy dopasowanie bez usuniętych odstępów w indeksie 5, więc zwraca 5, {1,2,3,4,5,7}. W czwartej parze zwracamy 7, {1,2,3,4,5,7}. W piątym zwróć 9, {1, 2, 3, 4, 5, 7}. W szóstym zwróć -1. W siódmym zwróć 13, {1, 2, 3, 4, 5, 7}. W ósmym zwróć -1.
Łącząc ponownie w cztery zestawy po cztery, mamy:
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})
Łączenie w zestawy po osiem:
10000101
: Return (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Zwrot (9, {4,7}), (13, {3,4,5,6,7})
Łączenie w zestaw szesnastu:
10000101 01000100
W miarę postępów sprawdzamy wszystkie dotychczasowe możliwości. Aż do tego kroku zostawialiśmy rzeczy, które wykraczały poza koniec łańcucha, ale teraz możemy sprawdzić wszystkie możliwości.
Zasadniczo sprawdzamy pierwszą 1 z odstępami 5 i 7 i stwierdzamy, że nie pokrywają się one z 1. (Zwróć uwagę, że każdy test jest STAŁY, a nie jest czasem liniowym) Następnie sprawdzamy drugi (indeks 5) z odstępami 2, 3, 4, 5, 6 i 7 - lub moglibyśmy, ale możemy zatrzymać się na 2, ponieważ to faktycznie pasuje.
Uff! To dość długi algorytm.
Nie wiem w 100%, czy to O (n log n) z powodu ostatniego kroku, ale wszystko, co tam jest, jest zdecydowanie O (n log n), o ile wiem. Wrócę do tego później i spróbuję udoskonalić ostatni krok.
EDYCJA: Zmieniłem moją odpowiedź, aby odzwierciedlić komentarz Welboga. Przepraszamy za błąd. Pseudokod napiszę później, gdy będę miał trochę więcej czasu na rozszyfrowanie tego, co napisałem ponownie. ;-)