Обновление .
Я должен полностью перефразировать свой ответ.(Если вы проголосовали за более раннюю версию, ну, вы были обмануты!)
Давайте снова подведем итог простого случая, чтобы убрать его с пути:
Найдите самый длинный префикс битовой строки, содержащей равное количество единиц и нулей массива.
Это тривиально: необходим простой счетчик, подсчитывающий, сколько еще единиц мы имеемчем 0, и итерации цепочки бит при сохранении этого.Позиция, в которой этот счетчик становится нулем в последний раз, является концом самого длинного искомого префикса.O (N) время, O (1) пространство.(Теперь я полностью убежден, что это то, о чем просила исходная проблема.)
Теперь давайте переключимся на более сложную версию проблемы: нам больше не нужно, чтобы подпоследовательности были префиксами - они могут начинаться где угодно.
После некоторых размышлений я подумал, что для этого не может быть линейного алгоритма.Например, рассмотрим префикс "111111111111111111 ...".Каждый 1 из них может быть началом самой длинной подпоследовательности, нет никакой начальной позиции подпоследовательности-кандидата, которая доминирует (то есть всегда дает лучшие решения, чем) любой другой позиции, поэтому мы не можем выбросить ни одну из них (O (N)пробел) и на любом шаге мы должны иметь возможность выбрать лучший старт (который имеет равное число 1 с и 0 с текущей позицией) из линейно большого числа кандидатов за O (1) времени. Оказывается, это выполнимо , и также легко выполнимо, так как мы можем выбрать кандидата на основе текущей суммы 1 с (+1) и 0 с (-1), это имеет не более размера N, имы можем сохранить первую позицию, которую достигнем каждой суммы, в 2N ячейках - см. ответ pmod ниже (комментарии yellowfog и геометрическая проницательность).
Не найдя этого трюка, я заменил быстрыйно неправильно с медленным, но уверенным алгоритмом (поскольку правильные алгоритмы предпочтительнее неправильных!):
- Построить массив
A
с накопленным числом 1 от начала до этой позиции, напримересли цепочка битов равна «001001001», то массив будет [0, 0, 1, 1, 1, 2, 2, 2, 3].Используя это, мы можем проверить в O (1), действительна ли подпоследовательность (i, j) включительно: isValid(i, j) = (j - i + 1 == 2 * (A[j] - A[i - 1])
, то есть она действительна, если ее длина вдвое больше, чем 1 в ней.Например, подпоследовательность (3,6) действительна, потому что 6 - 3 + 1 == 2 * A [6] - A [2] = 4. Простой старый двойной цикл:
maxSubsLength = 0 для i = 1 до N - 1 для j = i + 1 до N, если isValid (i, j) ... #maintain maxSubsLength end end
Это можно немного ускорить, используя некоторые ветвления и ограничения, пропуская i / j последовательности, которые короче текущего maxSubsLength, но асимптотически это все еще O (n ^ 2).Медленно, но с большим плюсом на боку: правильно!