Префикс-функция — различия между версиями
Sergej (обсуждение | вклад)  (→Построение строки по префикс-функции)  | 
				Sergej (обсуждение | вклад)   (→Построение строки по префикс-функции)  | 
				||
| Строка 61: | Строка 61: | ||
===Описание алгоритма===  | ===Описание алгоритма===  | ||
Пусть в массиве <tex>p</tex> хранятся значения префикс-функции,в <tex>s</tex> будет записан ответ. Пойдем по массиву <tex>p</tex> слева направо.  | Пусть в массиве <tex>p</tex> хранятся значения префикс-функции,в <tex>s</tex> будет записан ответ. Пойдем по массиву <tex>p</tex> слева направо.  | ||
| − | Пусть мы хотим узнать значение <tex>s[i]</tex>, посмотрим на значение <tex>p[i]</tex> если <tex>p[i] =0</tex> тогда в <tex>s[i]</tex> запишем новый символ, иначе <tex>s[i] = s[p[i]]</tex>  | + | Пусть мы хотим узнать значение <tex>s[i]</tex>, посмотрим на значение <tex>p[i]</tex> если <tex>p[i] =0</tex> тогда в <tex>s[i]</tex> запишем новый символ, иначе <tex>s[i] = s[p[i]]</tex>. Так как подстрока с 1 по <tex>p[i]</tex> заканчивается в <tex>s[i]</tex> то <tex>s[i]</tex> должен быть равен <tex>s[p[i]]</tex>  | 
| + | ===Псевдокод===  | ||
| + |  string s;  | ||
| + |  vector<int> p;  | ||
| + |  for (int i = 0; i < p.size(); i++)  | ||
| + |  {  | ||
| + |      if (p[i] == 0)  | ||
| + |      {  | ||
| + |          s += new char;  | ||
| + |      } else  | ||
| + |      {  | ||
| + |          s += s[p[i]];        | ||
| + |      }  | ||
| + |  }  | ||
== Литература ==  | == Литература ==  | ||
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296.  | Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296.  | ||
Версия 19:28, 23 апреля 2014
Префикс-функция строки — функция .
Содержание
Алгоритм
Наивный алгоритм вычисляет префикс функцию непосредственно по определению, сравнивая префиксы и суффиксы строк.
Псевдокод
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
Время работы
Время работы алгоритма составит . Для доказательства этого нужно заметить, что итоговое количество итераций цикла определяет асимптотику алгоритма. Теперь стоит отметить, что увеличивается на каждом шаге не более чем на единицу, значит максимально возможное значение . Поскольку внутри цикла значение лишь уменьшается, получается, что не может суммарно уменьшиться больше, чем раз. Значит цикл в итоге выполнится не более раз, что дает итоговую оценку времени алгоритма .
Построение строки по префикс-функции
Постановка задачи
Восстановить строку по префикс-функции за () (алфавит неограничен).
Описание алгоритма
Пусть в массиве хранятся значения префикс-функции,в будет записан ответ. Пойдем по массиву слева направо. Пусть мы хотим узнать значение , посмотрим на значение если тогда в запишем новый символ, иначе . Так как подстрока с 1 по заканчивается в то должен быть равен
Псевдокод
string s;
vector<int> p;
for (int i = 0; i < p.size(); i++)
{
    if (p[i] == 0)
    {
        s += new char;
    } else
    {
        s += s[p[i]];      
    }
}
Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.
