Изменения
→Более быстрый поиск
== Более быстрый поиск ==
Существует более быстрый алгоритм поиска образца в строке. Для этого используется <tex>\mathtt {lcp } </tex> (longest common prefix).
=== Условные обозначения ===
* <tex> M = (L + R) / 2 </tex>.
* <tex> l = </tex><tex>\mathtt {lcp}</tex><tex>(array[L], p) </tex>.* <tex> r = </tex><tex>\mathtt {lcp}</tex><tex>(array[R], p) </tex>.
В самом начале просто посчитаем <tex> l </tex> и <tex> r </tex> за линейное время, а во время выполнения алгоритма прямой пересчет производиться не будет, изменения будут происходить за <tex> O(1) </tex>.
* <tex> m_l = </tex><tex>\mathtt {lcp}</tex><tex>(array[L], array[M]) </tex>.* <tex> m_r = </tex><tex>\mathtt {lcp}</tex><tex>(array[M], array[R]) </tex>.
Подсчет <tex> m_l </tex> и <tex> m_r </tex> можно производить за <tex> O(1) </tex>, если применять [[Алгоритм Фарака-Колтона и Бендера|алгоритм Фарака-Колтона и Бендера]]. Любая пара суффиксов <tex> array </tex> из диапазона <tex> [L, M] </tex> имеет хотя бы <tex> m_l </tex> совпадений в префиксах. Аналогично любая пара суффиксов <tex> array </tex> из диапазона <tex> [M, R] </tex> имеет хотя бы <tex> m_r </tex> совпадений в префиксах.
'''Рисунки:'''
* Черная вертикальная линия на рисунке обозначает <tex>\mathtt {lcp } </tex> от <tex> i </tex>-го суффикса суффиксного массива <tex> array </tex> и образца <tex> p </tex>. Чем линия длиннее, тем совпадений символов больше. * <tex> L </tex>, <tex> M </tex> и <tex> R </tex> {{---}} то же самое, что в алгоритме. Кроме того, самая левая черная вертикальная линия на каждом рисунке означает <tex> l </tex>, аналогично, самая правая черная вертикальная линия на каждом рисунке означает <tex> r </tex>. Переменная <tex> m_l </tex> {{---}} это <tex>\mathtt {lcp } </tex> в суффиксном массиве на промежутке <tex> [L, M] </tex>. Переменная <tex> m_r </tex> {{---}} это <tex>\mathtt {lcp } </tex> в суффиксном массиве на промежутке <tex> [M, R] </tex>.* Серым цветом выделен <tex>\mathtt {lcp } </tex> в суффиксном массиве на рассматриваемом промежутке.
=== Поиск границ диапазона ответов ===
Если <tex> l < r </tex>, то действия аналогичны. Также три случая:
# <tex> m_r > r </tex>. Сдвигаем <tex> R </tex> в <tex> M </tex>. Значение <tex> r </tex> не изменяется.
# <tex> m_r = r </tex>. Считаем <tex>\mathtt {lcp } </tex> для образца и суффикса, стоящего в позиции <tex> M </tex>, начиная с позиции <tex> r </tex>.
# <tex> m_r < r </tex>. Сдвигаем <tex> L </tex> в <tex> M </tex>, <tex> l = m_r </tex>.
Рассуждения при поиске <tex> R_p </tex> аналогичны, только нужно не забыть изменить границы поиска на изначальные <tex> L = 0 </tex> и <tex> R = |s| - 1 </tex>.
Таким образом часть бинарного поиска мы сделаем при сравнении нескольких <tex>\mathtt {lcp } </tex> между собой(каждое за <tex> O(1) </tex>), а если дойдет до сравнения символов, то любой символ <tex> p </tex> сравнивается не более одного раза(при сравнении мы берем <tex>\mathtt max</tex><tex>(l, r) </tex>, а значит никогда не возвращаемся назад). В самом начале мы посчитали <tex> l </tex> и <tex> r </tex> за <tex> O(p) </tex>. В итоге получаем сложность алгоритма <tex> O(p + log(s)) </tex>. Правда нужен предподсчет, чтобы можно было брать <tex>\mathtt {lcp } </tex> для двух любых суффиксов <tex> array </tex> за <tex> O(1) </tex>, начиная с позиции <tex> r </tex>.
===Псевдокод===
Сравнения <tex>< , > , == , \leqslant , \geqslant </tex> при применении к строкам означают полное лексикографическое сравнение строк.
Функция <tex>\mathtt {lcp_z}</tex><tex>(s, p)</tex> ищет количество совпадений символов строк <tex>s</tex> и <tex>p</tex> начиная с позиции <tex>z</tex>.
<tex>n</tex> {{---}} длина строки <tex>s</tex>, <tex>w</tex> {{---}} длина строки <tex>p</tex>.