Algolume

Алгоритм Z-функции

Условие задачи: Дан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).

Решение: Мы поддерживаем окно [lr], в котором уже найдено совпадение с префиксом. Для каждой позиции i сначала берем z[i] = min(r - i + 1, z[i-l]), если i ≤ r, чтобы не проверять заново уже известные символы. Затем «дотягиваем» совпадение наивным сравнением символов дальше. Если новая правая граница превосходит r, сдвигаем l, r.
В итоге, алгоритм работает за линейное время и память O(n).

После выполнения цикла в z будут все значения Z-функции.

Например,

даёт

Доказательство корректности: Инвариант: перед обработкой i окно [lr] реально отражает максимум совпадения префикса, заканчивающегося не раньше r. При i≤r значение z[i-l] ― длина совпадения в зеркальной позиции, мы используем не больше чем гарантировано до r. Дальнейшее наивное расширение полностью проверяет оставшиеся символы. Для i>r мы начинаем сравнение с нуля, что корректно. Так все z[i] вычисляются без пропусков или переизбыточных проверок.

Пример реализации (Python 3)

Для корректной работы визуализации ограничения на входные данные следующие: 1 ≤ len(s) ≤ 30.

Логическое название Название переменной
Входная строка
Массив z-функции