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