Префикс-функция — различия между версиями
Vasin (обсуждение | вклад) (→Оптимизация) |
Vasin (обсуждение | вклад) (→Оптимизация) |
||
Строка 38: | Строка 38: | ||
==Оптимизация== | ==Оптимизация== | ||
Вносятся несколько важных замечаний: | Вносятся несколько важных замечаний: | ||
− | *Следует заметить, что <tex>\pi(i) \le \pi(i-1) + 1</tex>. По определению префикс функции верно, что <tex>s[1..\pi(i)] = s[i - pi(i)..i]</tex>. Отсюда получается, что <tex>s[1..\pi(i - 1)] = s[i - pi(i)..i - 1]</tex>. Поскольку <tex>\pi</tex> это наибольший префикс равный суффиксу, то <tex>pi(i - 1) >= pi(i) - 1</tex>. | + | *Следует заметить, что <tex>\pi(i) \le \pi(i-1) + 1</tex>. По определению префикс функции верно, что <tex>s[1..\pi(i)] = s[i - \pi(i)..i]</tex>. Отсюда получается, что <tex>s[1..\pi(i - 1)] = s[i - \pi(i)..i - 1]</tex>. Поскольку <tex>\pi</tex> это наибольший префикс равный суффиксу, то <tex>\pi(i - 1) >= \pi(i) - 1</tex>. |
*Избавимся от явных сравнений строк. Для этого подберем такое <tex>k</tex>, что <tex>k = \pi(i) - 1</tex>. После подбора достаточно будет сравнить <tex>s[k + 1]</tex> и <tex>s[i]</tex>, при их равенстве <tex>\pi(i) = k + 1</tex>. В другом случае продолжается поиск <tex>k</tex>, пока оно больше нуля. Если <tex>k=0</tex>, то <tex>\pi(i)=1</tex> при <tex>s[i] = s[1]</tex> , иначе <tex>\pi(i)=0</tex>. | *Избавимся от явных сравнений строк. Для этого подберем такое <tex>k</tex>, что <tex>k = \pi(i) - 1</tex>. После подбора достаточно будет сравнить <tex>s[k + 1]</tex> и <tex>s[i]</tex>, при их равенстве <tex>\pi(i) = k + 1</tex>. В другом случае продолжается поиск <tex>k</tex>, пока оно больше нуля. Если <tex>k=0</tex>, то <tex>\pi(i)=1</tex> при <tex>s[i] = s[1]</tex> , иначе <tex>\pi(i)=0</tex>. | ||
*За исходное <tex>k</tex> нужно взять <tex>\pi(i - 1)</tex>, что следует из первого пункта. В случае, когда символы <tex>s[k+1]</tex> и <tex>s[i]</tex> не совпадают, <tex>\pi(k)</tex> {{---}} следующая по максимальности длина потенциального наибольшего общего префикса, что видно из рисунка. Последнее утверждение верно, пока <tex>k>0</tex>, что позволит всегда найти его следующее значение. | *За исходное <tex>k</tex> нужно взять <tex>\pi(i - 1)</tex>, что следует из первого пункта. В случае, когда символы <tex>s[k+1]</tex> и <tex>s[i]</tex> не совпадают, <tex>\pi(k)</tex> {{---}} следующая по максимальности длина потенциального наибольшего общего префикса, что видно из рисунка. Последнее утверждение верно, пока <tex>k>0</tex>, что позволит всегда найти его следующее значение. |
Версия 16:34, 12 июня 2012
Префикс-функция строки
— функция , где принадлежит расширенному множеству натуральных чисел.Содержание
Алгоритм
Наивный алгоритм вычисляет префикс функцию непосредственно по определению, сравнивая префиксы и суффиксы строк.
Псевдокод
Prefix_function () = [0,..0] for i = 1 to n for k = 1 to i - 1 if s[1..k] == s[i - k + 1..i] [i] = k return
Пример
Рассмотрим строку abcabcd, для которой значение префикс-функции равно
.Шаг | Строка | Значение функции |
---|---|---|
a | 0 | |
ab | 0 | |
abc | 0 | |
abca | 1 | |
abcab | 2 | |
abcabc | 3 | |
abcabcd | 0 |
Время работы
Всего
итераций цикла, на каждой из который происходит сравнение строк за , что дает в итоге .Оптимизация
Вносятся несколько важных замечаний:
- Следует заметить, что . По определению префикс функции верно, что . Отсюда получается, что . Поскольку это наибольший префикс равный суффиксу, то .
- Избавимся от явных сравнений строк. Для этого подберем такое , что . После подбора достаточно будет сравнить и , при их равенстве . В другом случае продолжается поиск , пока оно больше нуля. Если , то при , иначе .
- За исходное нужно взять , что следует из первого пункта. В случае, когда символы и не совпадают, — следующая по максимальности длина потенциального наибольшего общего префикса, что видно из рисунка. Последнее утверждение верно, пока , что позволит всегда найти его следующее значение.
Псевдокод
Prefix_function () [1] = 0 k = 0 for i = 2 to n while k > 0 && s[i] != s[k + 1] k = [k] if s[i] == s[k + 1] k++ [i] = k return
Время работы
Время работы алгоритма составит
. Для доказательства этого нужно заметить, что итоговое количество итераций цикла составит время работы алгоритма. Теперь стоит отметить, что увеличивается на каждом шаге не более чем на единицу, значит максимально возможное значение . Внутри цикла значение лишь уменьшается, а из предыдущего утверждения получается, что оно не может суммарно уменьшиться больше, чем раз, значит цикл в итоге выполнится менее раз, что дает итоговую оценку времени алгоритма .Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.