Условие задачи: Данa строка s
длины n
. Нужно вычислить Z-функцию — массив z
длины n
, где
z[i]
равна максимальной длине подстроки, начинающейся с позиции i
и
совпадающей с префиксом строки.
Формат входных данных:
Первая строка — целое число n
(1 ≤ n ≤ 1 000 000
).
Вторая строка — сама строка s
длины n
(латиница, без пробелов).
Формат выходных данных: n
чисел
z[0] … z[n-1]
, разделённых пробелом (обычно z[0] = 0
).
Решение: Мы поддерживаем окно
[l
…r
], в котором уже найдено совпадение с префиксом. Для каждой позиции
i
сначала берем z[i] = min(r - i + 1, z[i-l])
, если i ≤ r
,
чтобы не
проверять заново уже известные символы. Затем «дотягиваем» совпадение наивным сравнением символов
дальше. Если новая правая граница превосходит r
, сдвигаем l, r
.
В итоге, алгоритм работает за линейное время и память O(n).
После выполнения цикла в z
будут все значения Z-функции.
Например,
даёт
Доказательство корректности:
Инвариант: перед обработкой i
окно [l
…r
] реально отражает
максимум совпадения префикса, заканчивающегося не раньше r
. При i≤r
значение z[i-l]
― длина совпадения в зеркальной позиции, мы используем не больше чем
гарантировано до r
. Дальнейшее наивное расширение полностью проверяет оставшиеся
символы. Для i>r
мы начинаем сравнение с нуля, что корректно. Так все z[i]
вычисляются без пропусков или переизбыточных проверок.