Изменения

Перейти к: навигация, поиск

Z-функция

113 байт добавлено, 23:14, 15 ноября 2017
Описание алгоритма
{{Определение
|definition = '''Z-функция''' (англ. ''Z-function'') от строки <tex>S</tex> и позиции <tex>x</tex> — это длина максимального префикса подстроки, начинающейся с позиции <tex>x</tex> в строке <tex>S</tex>, который одновременно является и префиксом всей строки <tex>S</tex>. Более формально, <tex>Z[i](s) = \max k \mid s[i\, \mathinner{\ldotp\ldotp}ldots \, i + k] = s[0 \mathinner{\ldotp\ldotp} ldots k]</tex>. <!-- проинлайнил \twodots из clrscode -->
Значение Z-функции от первой позиции не определено, поэтому его обычно приравнивают к нулю или к длине строки.
'''while''' i + zf[i] < n '''and''' s[zf[i]] == s[i + zf[i]]
zf[i]++
'''if''' i + zf[i] >= right
left = i
right = i + zf[i]
Нужно узнать значение <tex>s[i]</tex>. Для этого посмотрим на значение <tex>z[i]</tex>: если <tex>z[i] = 0</tex>, тогда в <tex>s[i]</tex> запишем ещё не использованный символ или последний использованный символ алфавита, если мы уже использовали все символы. Если <tex>z[i] \neq 0</tex>, то нам нужно записать префикс длины <tex>z[i]</tex> строки <tex>s</tex>. Но если при посимвольном записывании этого префикса в конец строки <tex>s</tex> мы нашли такой <tex>j</tex> (индекс последнего символа строки), что <tex>z[j]</tex> больше, чем длина оставшейся незаписанной части префикса, то мы перестаём писать этот префикс и пишем префикс длиной <tex>z[j]</tex> строки <tex>s</tex>.
Для правильной работы алгоритма, будем считать значение <tex>z[0]</tex> равным нулю.
Заметим, что не всегда удастся восстановить строку с ограниченным алфавитом неподходящего размера. Например, для строки <tex>abacaba</tex> массив Z-функций будет <tex>[0, 0, 1, 0, 3, 0, 1]</tex>. Используя двоичный алфавит, мы получим строку <tex>abababa</tex>, но её массив Z-функций отличается от исходного. Ошибка восстановления строки возникла, когда закончились новые символы алфавита.
===Описание алгоритма===
<br>
Пусть префикс функция хранится в массиве <tex>P[0 ... \ldots n - 1]</tex>. Z-функцию будем записывать в массив <tex>Z[0 ... \ldots n-1]</tex>. Заметим, что если <tex>P[i]>0</tex>, то мы можем заявить, что <tex>Z[i-P[i]+1]</tex> будет не меньше, чем <tex>P[i]</tex>.
<br>
<br>
<br>
<br>
Пусть в <tex>Z[i] = z > 0</tex>, рассмотрю <tex>j<z</tex>, <tex>Z[j]=k</tex> и <tex>Z[i+j]=k_1</tex>. Пусть <tex>b_1=s[0...\ldots k-1]</tex>, <tex>b_2=s[j...\ldots j+k-1]</tex>, <tex>b_3=s[0...\ldots z-1]</tex>. Тогда заметим, что <tex>b_3 = s[i...\ldots i+z-1]</tex> и тогда возможны три случая:
# <tex>k<k_1</tex>.
#: Тогда <tex>b_1 \subset s[0...\ldots k_1-1]=s[i+j...\ldots i+j+k_1-1]</tex> и тогда очевидно, что мы не можем увеличить значение <tex>Z[i+j]</tex> и надо рассматривать уже <tex>i=i+j</tex>.
# <tex>k<z-j</tex> и <tex>k>k_1</tex>.
#: Тогда <tex>b_1 = b_2 \subset b_3 = s[i...\ldots i+z-1] \Rightarrow b_1 = s[i+j...\ldots i+j+k-1]</tex> и тогда очевидно, что <tex>Z[i+j]</tex> можно увеличить до <tex>k</tex>.
# <tex>k>z-j</tex> и <tex>k>k_1</tex>.
#: Тогда <tex>b_1 = b_2 </tex>, но <tex>b_2</tex> не является подстрокой строки <tex>b_3</tex> (так как<tex>j+k-1 > z</tex>). Так как известно, что <tex>s[z] \ne s[i+z]</tex>, то <tex>s[0...\ldots z-j] = s[i+j...\ldots i+z-1]</tex> и тогда понятно, что <tex>Z[i+j]=z-j</tex>.
<br>
===Время работы===
Из описания алгоритма видно, что во втором цикле перезаписывается каждая позиция массива Внешний цикл <tex>Z\mathrm{while}</tex> не более одного отработает за <tex>O(n)</tex> итераций, так как внутри него <tex>i</tex> увеличивается не менее чем на <tex>1)</tex>. Значит время работы второго цикла составляет А внутренний цикл выполнит суммарно не более <tex>O(n)</tex>. Так же видноитераций, так как после него <tex>i</tex> увеличится на количество итераций внутреннего цикла, но <tex>i</tex> не может увеличиться более чем на <tex>n</tex>, что в первом цикле пробегается один раз каждая позиция массива так как каждое значение <tex>PZ[i]</tex>. Получается в итоге время работы алгоритма составляет не может превзойти <tex>O(n)</tex>.
== См. также ==
Анонимный участник

Навигация