Префикс-функция
Примеры
Если они не равны:
Хотим найти наибольшую позицию j
Переформулируем
Код
vector<int> prefix_function(string s) {
int n = (int) s.size();
vector<int> p(n, 0);
for (int i = 1; i < n; i++) {
// префикс функция точно не больше этого значения + 1
int cur = p[i - 1];
// уменьшаем cur значение, пока новый символ не сматчится
while (s[i] != s[cur] && cur > 0)
cur = p[cur - 1];
// здесь либо s[i] == s[cur], либо cur == 0
if (s[i] == s[cur])
p[i] = cur + 1;
}
return p;
}
Задачи
Поиск подстроки в строке. Алгоритм Кнута-Морриса-Пратта
Дан текст t и слово s
Делаем s + ‘#’ + t. Находим префикс функцию. Проверяем равенство.
Количество различных подстрок в строке
Дописываем очередной символ. Инвертируем. Ищем префикс функцию.
Z-функция
2 случая
vector<int> z_function(string s) {
int n = (int) s.size();
vector<int> z(n, 0);
int l = 0, r = 0;
for (int i = 1; i < n; i++) {
// если мы уже видели этот символ
if (i <= r)
// то мы можем попробовать его инициализировать z[i - l],
// но не дальше правой границы: там мы уже ничего не знаем
z[i] = min(r - i + 1, z[i - l]);
// дальше каждое успешное увеличение z[i] сдвинет z-блок на единицу
while (i + z[i] < n && s[z[i]] == s[i + z[i]])
z[i]++;
// проверим, правее ли мы текущего z-блока
if (i + z[i] - 1 > r) {
r = i + z[i] - 1;
l = i;
}
}
return z;
}
Асимптотика В алгоритме мы делаем столько же действий, сколько раз сдвигается правая граница z-блока — а это O(n).
Алгоритм Манакера
Идея такая же как в зет функции
vector<int> d1 (n);
int l=0, r=-1;
for (int i=0; i<n; ++i) {
int k = i>r ? 1 : min (d1[l+r-i], r-i+1);
while (i+k < n && i-k >= 0 && s[i+k] == s[i-k]) ++k;
d1[i] = k;
if (i+k-1 > r)
l = i-k+1, r = i+k-1;
}
Домашнее задание
- Разобраться в префикс и зет функциях. Для тех, кто не понял ничего на паре - есть специальный образовательный раздел на кодфорсесе. Есть видосики, где последовательно, более структурировано обьясняют. Также присутствуют другие интересные материалы, например, по дереву отрезков.
- Написать контест. Как только я его составлю - добавлю сюда. Составлять буду из задач из предыдущего пункта.