Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа — различия между версиями
Martoon (обсуждение | вклад) м (→Метод хеширования) |
Martoon (обсуждение | вклад) (Добавлен пример строки когда алгоритм не работает) |
||
Строка 42: | Строка 42: | ||
Изначальный подсчёт хешей выполняется за <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>. | ||
+ | |||
+ | == Надёжность == | ||
+ | Если количество подстрок данной строки близко к количеству хешей, то наступление [[Разрешение_коллизий | коллизий]] очень вероятно. Но даже при относительно небольших строках возможны частые ложные срабатывания. | ||
+ | |||
+ | Например если взять <tex> r = 2^{32}, p = 237 </tex>, за <tex> s </tex> принять [[Слово_Туэ-Морса | строку Туэ-Морса]]<ref>[http://codeforces.ru/blog/entry/4898 Codeforces: Anti-hash test]</ref> длиной <tex> 1024 </tex> , то алгоритм находит лишние вхождения почти в половине случаев. | ||
+ | |||
+ | == Примечания == | ||
+ | <references> | ||
+ | </references> | ||
== Литература == | == Литература == | ||
Строка 48: | Строка 57: | ||
==Ссылки== | ==Ссылки== | ||
*[[Наивный алгоритм поиска подстроки в строке]] | *[[Наивный алгоритм поиска подстроки в строке]] | ||
+ | *[http://codeforces.ru/blog/entry/4898 Codeforces: Anti-hash test] | ||
[[Категория:Алгоритмы и структуры данных]] | [[Категория:Алгоритмы и структуры данных]] | ||
[[Категория:Поиск подстроки в строке]] | [[Категория:Поиск подстроки в строке]] | ||
[[Категория: Хеширование]] | [[Категория: Хеширование]] |
Версия 19:44, 6 мая 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 h < 0
h += r
if answer.size() == 0
return not found
else
return answer
Новый хеш
был получен с помощью быстрого пересчёта. Для сохранения корректности алгоритма нужно считать, что — пустой символ.Время работы
Изначальный подсчёт хешей выполняется за
. В цикле всего итераций, каждая выполняется за . Итоговое время работы алгоритма .Надёжность
Если количество подстрок данной строки близко к количеству хешей, то наступление коллизий очень вероятно. Но даже при относительно небольших строках возможны частые ложные срабатывания.
Например если взять строку Туэ-Морса[1] длиной , то алгоритм находит лишние вхождения почти в половине случаев.
, за принятьПримечания
Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.