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