Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа — различия между версиями
Vasin (обсуждение | вклад) (→Время работы) |
Vasin (обсуждение | вклад) (→Метод хеширования) |
||
Строка 2: | Строка 2: | ||
==Метод хеширования== | ==Метод хеширования== | ||
− | Для решения задачи удобно использовать полиномиальный хеш, так его легко пересчитывать: <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n]) \bmod r</tex>, где <tex>p</tex> {{---}} это некоторое простое число, а <tex>r</tex> {{---}} некоторое большое число, | + | Для решения задачи удобно использовать полиномиальный хеш, так его легко пересчитывать: <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n]) \bmod 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>: |
Версия 13:53, 10 июня 2012
Алгоритм Рабина-Карпа предназначен для поиска подстроки в строке.
Метод хеширования
Для решения задачи удобно использовать полиномиальный хеш, так его легко пересчитывать:
, где — это некоторое простое число, а — некоторое большое число, для уменьшения числа коллизий (обычно берётся или , чтобы модуль брался автоматически при переполнении типов). Стоит обратить внимание, что если 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])) mod r
if h < 0
h += r
if answer.size() == 0
return not found
else
return answer
Новый хеш
был получен с помощью быстрого пересчёта. Для сохранения корректности алгоритма нужно считать, что — пустой символ.Время работы
Изначальный подсчёт хешей выполняется за
. В цикле всего итераций, каждая выполняется за . Итоговое время работы алгоритма .Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.