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