Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа — различия между версиями
(→Псевдокод) |
|||
Строка 1: | Строка 1: | ||
− | Алгоритм Рабина | + | Алгоритм Рабина {{---}} Карпа {{---}} это алгоритм поиска подстроки в строке, используя хеширование. |
==Метод хеширования== | ==Метод хеширования== | ||
− | Следует использовать полиномиальный хеш - <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])</tex> mod <tex>r</tex>, где <tex>p</tex> - это некоторое простое число, а <tex>r</tex> - некоторое большое число, чтобы было меньше коллизий (обычно берётся <tex>2^{32}</tex> или <tex>2^{64}</tex>, чтобы модуль брался автоматически | + | Следует использовать полиномиальный хеш {{---}} <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])</tex> mod <tex>r</tex>, где <tex>p</tex> {{---}} это некоторое простое число, а <tex>r</tex> {{---}} некоторое большое число, чтобы было меньше коллизий (обычно берётся <tex>2^{32}</tex> или <tex>2^{64}</tex>, чтобы модуль брался автоматически при переполнении типов. Стоит обратить внимание, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны. |
При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за <tex>O(1)</tex>: | При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за <tex>O(1)</tex>: | ||
Строка 15: | Строка 15: | ||
==Алгоритм== | ==Алгоритм== | ||
− | Есть шаблон - <tex>p[1..m]</tex> и строка - <tex>s[1..n]</tex>. Нужно найти все вхождения шаблона в строку. | + | Есть шаблон {{---}} <tex>p[1..m]</tex> и строка {{---}} <tex>s[1..n]</tex>. Нужно найти все вхождения шаблона в строку. |
В начале вычисляются <tex>hash(s[1..m])</tex> и <tex>hash(p[1..m])</tex>. | В начале вычисляются <tex>hash(s[1..m])</tex> и <tex>hash(p[1..m])</tex>. | ||
− | Для <tex>i \in [1..n - m + 1]</tex> вычисляется <tex>hash(s[i..i + m - 1]</tex> и сравнивается с <tex>hash(p[1..m])</tex>. Если они получаются равными - то считается, что подстрока <tex>p</tex> входит в строку <tex>s</tex> (начиная с позиции <tex>i</tex>;) или проверяется, что подстрока является шаблоном, для этого выбираются и сравниваются случайные символы из строк. | + | Для <tex>i \in [1..n - m + 1]</tex> вычисляется <tex>hash(s[i..i + m - 1]</tex> и сравнивается с <tex>hash(p[1..m])</tex>. Если они получаются равными {{---}} то считается, что подстрока <tex>p</tex> входит в строку <tex>s</tex> (начиная с позиции <tex>i</tex>;) или проверяется, что подстрока является шаблоном, для этого выбираются и сравниваются случайные символы из строк. |
Следует предподсчитать <tex>p^{m}</tex>. | Следует предподсчитать <tex>p^{m}</tex>. | ||
Строка 36: | Строка 36: | ||
'''return''' answer | '''return''' answer | ||
− | Новый хеш h был получен с помощью быстрого пересчёта. Следует считать, что s[n + 1] - пустой символ. | + | Новый хеш <tex>h</tex> был получен с помощью быстрого пересчёта. Следует считать, что <tex>s[n + 1]</tex> - пустой символ. |
==Время работы== | ==Время работы== | ||
− | Изначальный подсчёт хешей - <tex>O(m)</tex>. В цикле всего <tex>n - m + 1</tex> итераций - каждая выполняется за <tex>O(1)</tex>. Итого - <tex>O(n + m)</tex>. | + | Изначальный подсчёт хешей {{---}} <tex>O(m)</tex>. В цикле всего <tex>n - m + 1</tex> итераций - каждая выполняется за <tex>O(1)</tex>. Итого {{---}} <tex>O(n + m)</tex>. |
== Литература == | == Литература == | ||
− | Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. | + | Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296. |
Версия 13:40, 4 апреля 2012
Алгоритм Рабина — Карпа — это алгоритм поиска подстроки в строке, используя хеширование.
Метод хеширования
Следует использовать полиномиальный хеш —
mod , где — это некоторое простое число, а — некоторое большое число, чтобы было меньше коллизий (обычно берётся или , чтобы модуль брался автоматически при переполнении типов. Стоит обратить внимание, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны.При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за
:.
.
Получается :
.Алгоритм
Есть шаблон —
и строка — . Нужно найти все вхождения шаблона в строку.В начале вычисляются
и .Для
вычисляется и сравнивается с . Если они получаются равными — то считается, что подстрока входит в строку (начиная с позиции ;) или проверяется, что подстрока является шаблоном, для этого выбираются и сравниваются случайные символы из строк.Следует предподсчитать
.Псевдокод
RabinKarp (s[1..n], p[1..m])
hp = hash(p[1..m])
h = hash(s[1..m])
for i = 1 to n - m + 1
if h = hp
answer.add(i)
h = p * h - p
* hash(s[i]) + hash(s[i + m)
if answer.size() == 0
return not found
else
return answer
Новый хеш
был получен с помощью быстрого пересчёта. Следует считать, что - пустой символ.Время работы
Изначальный подсчёт хешей —
. В цикле всего итераций - каждая выполняется за . Итого — .Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.