Условие задачи:
Дана строка s
длины n
. Требуется вычислить префикс-функцию — массив p
длины n
, где p[i]
равно длине наибольшего собственного префикса подстроки
s[0…i]
, совпадающего с её суффиксом.
Формат входных данных:
Первая строка — целое число n
(1 ≤ n ≤ 1 000 000
).
Вторая строка — сама строка s
длины n
(латиница, без пробелов).
Формат выходных данных:
n
чисел p[0] … p[n-1]
, разделённых пробелом (как правило p[0] =
0
).
Решение:
Поддерживаем переменную k
— значение p[i-1]
.
Для позиции i
уменьшением k ← p[k-1]
«поднимаемся» по ссылкам, пока
символы s[i]
и s[k]
не совпадут или k = 0
.
Если совпали, увеличиваем k++
и сохраняем p[i] = k
.
Алгоритм обходит строку один раз, сложность O(n)
, память O(n)
.
После цикла массив p
содержит префикс-функцию.
Например,
даёт
Доказательство корректности (скетч):
Инвариант: перед обработкой позиции i
переменная k
равна
p[i-1]
.
Цикл while
гарантирует, что после выхода k
— длина наибольшего
собственного префикса, совпадающего с суффиксом s[0…i-1]
, который ещё может
расшириться символом s[i]
. Если расширение возможно, прибавляем 1; иначе
p[i]=0
. Следовательно, каждое p[i]
корректно, а работа линейна, так как
k
только уменьшается внутри цикла.