Я думал о подходе «разделяй и властвуй», который может сработать.
Во-первых, при предварительной обработке вам нужно вставить все числа, меньшие половины вашего размера ввода ( n / 3), в список.
Учитывая строку: 0000010101000100
(обратите внимание, что этот конкретный пример действителен)
Вставьте все простые числа (и 1) от 1 до (16/2) в список: {1, 2, 3, 4, 5, 6, 7}
Затем разделите его пополам:
100000101 01000100
Продолжайте делать это, пока не доберетесь до строк размера 1. Для всех строк размера один с 1 в них добавьте индекс строки в список возможностей; в противном случае верните -1 в случае ошибки.
Вам также нужно будет вернуть список возможных расстояний, связанных с каждым начальным индексом. . в противном случае список включает в себя интервалы, которые должны быть исключены.
Итак, продолжаем с примером выше:
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
На первом шаге объединения у нас теперь восемь комплектов по два. Во-первых, у нас есть возможность множества, но мы узнаем, что интервал на 1 невозможен из-за присутствия другого нуля. Таким образом, мы возвращаем 0 (для индекса) и {2,3,4,5,7} за то, что интервал на 1 невозможен. Во втором у нас ничего нет и поэтому возвращаем -1. В третьем случае мы имеем совпадение без пропусков в индексе 5, поэтому возвращаем 5, {1,2,3,4,5,7}. В четвертой паре мы возвращаем 7, {1,2,3,4,5,7}. В пятом верните 9, {1,2,3,4,5,7}. В шестой верните -1. В седьмом верните 13, {1,2,3,4,5,7}. В восьмом верните -1.
Объединяя снова в четыре набора из четырех, мы имеем:
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
: Возврат (9, {3,4,5,6,7})
0100
: Возврат (13, {3,4,5,6,7})
Объединение в наборы из восьми:
10000101
: Return (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Возврат (9, {4,7}), (13, {3,4,5,6,7})
Объединение в набор из шестнадцати:
10000101 01000100
По мере нашего продвижения, мы продолжаем проверять все возможности до сих пор. До этого шага мы оставили вещи, которые выходили за пределы конца строки, но теперь мы можем проверить все возможности.
По сути, мы проверяем первые 1 с интервалами 5 и 7 и обнаруживаем, что они не совпадают с 1. (Обратите внимание, что каждая проверка является ПОСТОЯННОЙ, а не линейным временем) Затем мы проверяем вторую (индекс 5) с интервалами 2, 3, 4, 5, 6 и 7 - или мы бы это сделали, но мы можем остановиться на 2, так как это на самом деле совпадает.
Уф! Это довольно длинный алгоритм.
Я не знаю 100%, если это O (n log n) из-за последнего шага, но, насколько я могу судить , все, что там есть, определенно O (n log n) . Я вернусь к этому позже и попытаюсь уточнить последний шаг.
РЕДАКТИРОВАТЬ: изменил мой ответ, чтобы отразить комментарий Велбога. Извините за ошибку. Я также напишу немного псевдокода позже, когда у меня будет немного больше времени, чтобы расшифровать то, что я написал снова. ;-)