Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа — различия между версиями
(→Алгоритм) |
(→Алгоритм) |
||
Строка 15: | Строка 15: | ||
Алгоритм начинается с подсчета <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>. |
Версия 01:22, 18 апреля 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.