Вы находитесь на странице: 1из 17

Алгоритмы программирования и структуры данных

Поиск подстрок

Поиск подстрок (часть 4).


Z-функция
Z-функция

i
ABABABACABA
ABABABACABA
z[i]

z[i] = длина наибольшей подстроки, начинающейся в позиции i и равной


префиксу той же длины.
2
Z-функция

ABABABACABA
z -0503010301

2
Простой алгоритм

for i = 1..n - 1:
j = 0
while i+j < n && s[i+j] == s[j]:
j++
z[i] = j

Время работы: O(N2)


3
Худший случай

AAAAAAAAAA
z -987654321

4
Z-блоки

ABABABACABA
z -0503010301

Z-блок – подстрока от i до (i + z[i] – 1).

5
Самый правый Z-блок

L R

ABABABACABA
z -050.......

Храним z-блок [L..R – 1] с наибольшим R.

6
Случай 1

i≥R
LR
i
ABACABACABA
z -010.......

Жадно добавляем символы, как в простом алгоритме.

7
Случай 1

i≥R LR
i
ABACABACACA
z -0105......

Обновляем L и R.

7
Случай 2

i<R L R
i
ABABABACABA
z -05........

Мы знаем про символы с номерами j = i..R-1, что S[j] = S[j – L], их уже
сравнивали в Z[i – L].
8
Случай 2.1

z[i – L] < R – i L R
i
ABABABACABA
z -050.......

z[i] = z[i – L].

9
Случай 2.2

z[i – L] ≥ R – i L R
i
ABABABACABA
z -0503......

z[i] – не меньше R – i.

10
Случай 2.2

z[i – L] ≥ R – i L R
i
ABABCABABABC
z -0200405....

Жадно добавляем символы, начиная с R.

10
Случай 2.2

z[i – L] ≥ R – i L R
i
ABABCABABABC
z -0200405....

Обновляем L и R.

10
Построение Z-функции. Код
L = 0, R = 0
for i = 1 .. n − 1
if i >= R:
j = 0
while i + j < n && s[i + j] == s[j]:
j++
L = i, R = i + j
z[i] = j
else:
if z[i – L] < R – i:
z[i] = z[i – L]
else:
j = R - i
while i + j < n && s[i + j] == s[j]:
j++
L = i, R = i + j
z[i] = j

Время работы: O(N) 11


Анализ времени работы
L = 0, R = 0
for i = 1 .. n − 1
if i >= R:
j = 0 // R <= i + j
while i + j < n && s[i + j] == s[j]:
j++ // R увеличивается
L = i, R = i + j
z[i] = j
else:
if z[i – L] < R – i:
z[i] = z[i – L]
else:
j = R - i // R = i + j
while i + j < n && s[i + j] == s[j]:
j++ // R увеличивается
L = i, R = i + j
z[i] = j

Время работы: O(N) 12


Поиск подстроки

BABABCABACBAD
ABAC

ABAC#BABABCABACBAD
z -01000302004......

13