<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=185.102.11.243&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=185.102.11.243&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/185.102.11.243"/>
		<updated>2026-04-16T05:55:52Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=75084</id>
		<title>Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=75084"/>
				<updated>2020-10-08T04:53:17Z</updated>
		
		<summary type="html">&lt;p&gt;185.102.11.243: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Рабина-Карпа предназначен для [[Наивный алгоритм поиска подстроки в строке#Постановка задачи| поиска подстроки в строке]].&lt;br /&gt;
==Метод хеширования==&lt;br /&gt;
&lt;br /&gt;
[[Наивный алгоритм поиска подстроки в строке]] работает за &amp;lt;tex&amp;gt;O\left(n^2\right)&amp;lt;/tex&amp;gt; в худшем случае — слишком долго. Чтобы ускорить этот процесс, можно воспользоваться методом [[Хеш-таблица#Хеширование|хеширования]].&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = Пусть дана строка &amp;lt;tex&amp;gt;s[0..n-1]&amp;lt;/tex&amp;gt;. Тогда '''полиномиальным хешем''' (англ. ''polynomial hash'') строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; называется число &amp;lt;tex&amp;gt;h = \mathrm{hash}(s[0..n-1]) =  p^{0} s[0] + ... + p^{n - 1} s[n-1]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; — некоторое простое число, а &amp;lt;tex&amp;gt;s[i]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; код &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ого символа строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Проблему переполнения при вычислении хешей довольно больших строк можно решить так &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; считать хеши по модулю &amp;lt;tex&amp;gt;r=2^{64}&amp;lt;/tex&amp;gt; (или &amp;lt;tex&amp;gt;2^{32}&amp;lt;/tex&amp;gt;), чтобы модуль брался автоматически при переполнении типов.&lt;br /&gt;
&lt;br /&gt;
Для работы алгоритма потребуется считать хеш подстроки &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt;. Делать это можно следующим образом:&lt;br /&gt;
&lt;br /&gt;
Рассмотрим хеш &amp;lt;tex&amp;gt;s[0..j]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = s[0] + p s[1] +...+ p^{i-1} s[i-1] + p^{i} s[i] +...+ p^{j-1} s[j-1] + p^{j} s[j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разобьем это выражение на две части:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = (s[0] + p s[1] +...+ p^{i-1} s[i-1]) + (p^{i} s[i] +...+ p^{j-1} s[j-1] + p^{j} s[j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вынесем из последней скобки множитель &amp;lt;tex&amp;gt;p^{i}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = (s[0] + p s[1] +...+ p^{i-1} s[i-1]) + p^{i}(s[i] +...+ p^{j-i-1} s[j-1] + p^{j-i} s[j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выражение в первой скобке есть не что иное, как хеш подстроки &amp;lt;tex&amp;gt;s[0..i-1]&amp;lt;/tex&amp;gt;, а во второй — хеш нужной нам подстроки &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt;. Итак, мы получили, что:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = \mathrm{hash}(s[0..i-1]) + p^{i}\mathrm{hash}(s[i..j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсюда получается следующая формула для &amp;lt;tex&amp;gt;\mathrm{hash}(s[i..j])&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i..j]) = (1/p^{i})(\mathrm{hash}(s[0..j]) - \mathrm{hash}(s[0..i-1]))&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Однако, как видно из формулы, чтобы уметь считать хеш для всех подстрок начинающихся с &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, нужно предпосчитать все &amp;lt;tex&amp;gt;p^{i}&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;i \in [0..n - 1]&amp;lt;/tex&amp;gt;. Это займет много памяти. Но поскольку нам нужны только подстроки размером &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; мы можем подсчитать хеш подстроки &amp;lt;tex&amp;gt;s[0..m-1]&amp;lt;/tex&amp;gt;, а затем пересчитывать хеши для всех &amp;lt;tex&amp;gt;i \in [0..n - m]&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m - 1]) = (\mathrm{hash}(s[i..i + m - 1]) - p^{m - 1} s[i]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m]) = (p \cdot \mathrm{hash}(s[i + 1..i + m - 1]) + s[i + m]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Получается : &amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m]) = (p \cdot \mathrm{hash}(s[i..i + m - 1]) - p^{m} s[i] + s[i + m]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Решение==&lt;br /&gt;
&lt;br /&gt;
===Алгоритм===&lt;br /&gt;
&lt;br /&gt;
Алгоритм начинается с подсчета &amp;lt;tex&amp;gt;\mathrm{hash}(s[0..m-1])&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{hash}(p[0..m-1])&amp;lt;/tex&amp;gt;, а также с подсчета &amp;lt;tex&amp;gt;p^{m}&amp;lt;/tex&amp;gt;, для ускорения ответов на запрос.&lt;br /&gt;
&lt;br /&gt;
Для &amp;lt;tex&amp;gt;i \in [0..n - m]&amp;lt;/tex&amp;gt; вычисляется &amp;lt;tex&amp;gt;\mathrm{hash}(s[i..i + m - 1])&amp;lt;/tex&amp;gt; и сравнивается с &amp;lt;tex&amp;gt;\mathrm{hash}(p[0..m-1])&amp;lt;/tex&amp;gt;. Если они оказались равны, то образец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; скорее всего содержится в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; начиная с позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, хотя возможны и ложные срабатывания алгоритма. Если требуется свести такие срабатывания к минимуму или исключить вовсе, то применяют сравнение некоторых символов из этих строк, которые выбраны случайным образом, или применяют явное сравнение строк, как в [[Наивный алгоритм поиска подстроки в строке|наивном алгоритме поиска подстроки в строке]]. В первом случае проверка произойдет быстрее, но вероятность ложного срабатывания, хоть и небольшая, останется. Во втором случае проверка займет время, равное длине образца, но полностью исключит возможность ложного срабатывания. &lt;br /&gt;
&lt;br /&gt;
Если требуется найти индексы вхождения нескольких образцов, или сравнить две строки &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; выгоднее будет предпосчитать все степени &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а также хеши всех префиксов строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем пример псевдокода, который находит все вхождения строки &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; в строку &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и возвращает массив позиций, откуда начинаются вхождения.&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' rabinKarp (s : '''string''', w : '''string'''):&lt;br /&gt;
    '''vector&amp;lt;int&amp;gt;''' answer&lt;br /&gt;
    '''int''' n = s.length&lt;br /&gt;
    '''int''' m = w.length&lt;br /&gt;
    '''int''' hashS = hash(s[0..m - 1])&lt;br /&gt;
    '''int''' hashW = hash(w[0..m - 1])&lt;br /&gt;
    '''for''' i = 0 '''to''' n - m&lt;br /&gt;
         '''if''' hashS == hashW&lt;br /&gt;
              answer.add(i)&lt;br /&gt;
         hashS = (p * hashS - p&amp;lt;tex&amp;gt;^{m}&amp;lt;/tex&amp;gt; * hash(s[i]) + hash(s[i + m])) '''mod''' r &amp;lt;font color=green&amp;gt;// r — некоторое большое число, p — некоторое просто число&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Новый хеш &amp;lt;tex&amp;gt;hashS&amp;lt;/tex&amp;gt; был получен с помощью быстрого пересчёта. Для сохранения корректности алгоритма нужно считать, что &amp;lt;tex&amp;gt;s[n + 1]&amp;lt;/tex&amp;gt; {{---}} пустой символ.&lt;br /&gt;
&lt;br /&gt;
===Время работы===&lt;br /&gt;
&lt;br /&gt;
Изначальный подсчёт хешей выполняется за &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Каждая итерация выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, В цикле всего &amp;lt;tex&amp;gt;n - m + 1&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Однако, если требуется исключить ложные срабатывания алгоритма полностью, т.е. придется проверить все полученные позиции вхождения на истинность, то в худшем случае итоговое время работы алгоритма будет &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Сравнение с другими алгоритмами ==&lt;br /&gt;
Преимущества:&lt;br /&gt;
* Быстрая скорость работы — &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки, &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; — длина образца;&lt;br /&gt;
* Простая и понятная реализация;&lt;br /&gt;
&lt;br /&gt;
Недостатки:&lt;br /&gt;
* Возможно подобрать входные данные так, что количество ложных срабатываний будет недопустимо большим;&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Наивный алгоритм поиска подстроки в строке]]&lt;br /&gt;
*[[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* ''Кормен, Томас Х., Лейзерсон, Чарльз И., Ривест, Рональд Л., Штайн Клиффорд'' '''Алгоритмы: построение и анализ''', 3-е издание. Пер. с англ. — М.:Издательский дом &amp;quot;Вильямс&amp;quot;, 2014. — 1328 с.: ил. — ISBN 978-5-8459-1794-2 (рус.) — страницы 1036–1041.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Поиск подстроки в строке]]&lt;br /&gt;
[[Категория: Хеширование]]&lt;br /&gt;
[[Категория:Точный поиск]]&lt;/div&gt;</summary>
		<author><name>185.102.11.243</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=75083</id>
		<title>Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=75083"/>
				<updated>2020-10-08T04:52:48Z</updated>
		
		<summary type="html">&lt;p&gt;185.102.11.243: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Рабина-Карпа предназначен для [[Наивный алгоритм поиска подстроки в строке#Постановка задачи| поиска подстроки в строке]].&lt;br /&gt;
==Метод хеширования==&lt;br /&gt;
&lt;br /&gt;
[[Наивный алгоритм поиска подстроки в строке]] работает за &amp;lt;tex&amp;gt;O\left(n^2\right)&amp;lt;/tex&amp;gt; в худшем случае — слишком долго. Чтобы ускорить этот процесс, можно воспользоваться методом [[Хеш-таблица#Хеширование|хеширования]].&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = Пусть дана строка &amp;lt;tex&amp;gt;s[0..n-1]&amp;lt;/tex&amp;gt;. Тогда '''полиномиальным хешем''' (англ. ''polynomial hash'') строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; называется число &amp;lt;tex&amp;gt;h = \mathrm{hash}(s[0..n-1]) =  p^{0} s[0] + ... + p^{n - 1} s[n-1]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; — некоторое простое число, а &amp;lt;tex&amp;gt;s[i]&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; код &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ого символа строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Проблему переполнения при вычислении хешей довольно больших строк можно решить так &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; считать хеши по модулю &amp;lt;tex&amp;gt;r=2^{64}&amp;lt;/tex&amp;gt; (или &amp;lt;tex&amp;gt;2^{32}&amp;lt;/tex&amp;gt;), чтобы модуль брался автоматически при переполнении типов.&lt;br /&gt;
&lt;br /&gt;
Для работы алгоритма потребуется считать хеш подстроки &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt;. Делать это можно следующим образом:&lt;br /&gt;
&lt;br /&gt;
Рассмотрим хеш &amp;lt;tex&amp;gt;s[0..j]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = s[0] + p s[1] +...+ p^{i-1} s[i-1] + p^{i} s[i] +...+ p^{j-1} s[j-1] + p^{j} s[j]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разобьем это выражение на две части:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = (s[0] + p s[1] +...+ p^{i-1} s[i-1]) + (p^{i} s[i] +...+ p^{j-1} s[j-1] + p^{j} s[j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вынесем из последней скобки множитель &amp;lt;tex&amp;gt;p^{i}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = (s[0] + p s[1] +...+ p^{i-1} s[i-1) + p^{i}(s[i] +...+ p^{j-i-1} s[j-1] + p^{j-i} s[j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выражение в первой скобке есть не что иное, как хеш подстроки &amp;lt;tex&amp;gt;s[0..i-1]&amp;lt;/tex&amp;gt;, а во второй — хеш нужной нам подстроки &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt;. Итак, мы получили, что:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[0..j]) = \mathrm{hash}(s[0..i-1]) + p^{i}\mathrm{hash}(s[i..j])&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсюда получается следующая формула для &amp;lt;tex&amp;gt;\mathrm{hash}(s[i..j])&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i..j]) = (1/p^{i})(\mathrm{hash}(s[0..j]) - \mathrm{hash}(s[0..i-1]))&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Однако, как видно из формулы, чтобы уметь считать хеш для всех подстрок начинающихся с &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, нужно предпосчитать все &amp;lt;tex&amp;gt;p^{i}&amp;lt;/tex&amp;gt; для &amp;lt;tex&amp;gt;i \in [0..n - 1]&amp;lt;/tex&amp;gt;. Это займет много памяти. Но поскольку нам нужны только подстроки размером &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; мы можем подсчитать хеш подстроки &amp;lt;tex&amp;gt;s[0..m-1]&amp;lt;/tex&amp;gt;, а затем пересчитывать хеши для всех &amp;lt;tex&amp;gt;i \in [0..n - m]&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m - 1]) = (\mathrm{hash}(s[i..i + m - 1]) - p^{m - 1} s[i]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m]) = (p \cdot \mathrm{hash}(s[i + 1..i + m - 1]) + s[i + m]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Получается : &amp;lt;tex&amp;gt;\mathrm{hash}(s[i + 1..i + m]) = (p \cdot \mathrm{hash}(s[i..i + m - 1]) - p^{m} s[i] + s[i + m]) \bmod r&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Решение==&lt;br /&gt;
&lt;br /&gt;
===Алгоритм===&lt;br /&gt;
&lt;br /&gt;
Алгоритм начинается с подсчета &amp;lt;tex&amp;gt;\mathrm{hash}(s[0..m-1])&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{hash}(p[0..m-1])&amp;lt;/tex&amp;gt;, а также с подсчета &amp;lt;tex&amp;gt;p^{m}&amp;lt;/tex&amp;gt;, для ускорения ответов на запрос.&lt;br /&gt;
&lt;br /&gt;
Для &amp;lt;tex&amp;gt;i \in [0..n - m]&amp;lt;/tex&amp;gt; вычисляется &amp;lt;tex&amp;gt;\mathrm{hash}(s[i..i + m - 1])&amp;lt;/tex&amp;gt; и сравнивается с &amp;lt;tex&amp;gt;\mathrm{hash}(p[0..m-1])&amp;lt;/tex&amp;gt;. Если они оказались равны, то образец &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; скорее всего содержится в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; начиная с позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, хотя возможны и ложные срабатывания алгоритма. Если требуется свести такие срабатывания к минимуму или исключить вовсе, то применяют сравнение некоторых символов из этих строк, которые выбраны случайным образом, или применяют явное сравнение строк, как в [[Наивный алгоритм поиска подстроки в строке|наивном алгоритме поиска подстроки в строке]]. В первом случае проверка произойдет быстрее, но вероятность ложного срабатывания, хоть и небольшая, останется. Во втором случае проверка займет время, равное длине образца, но полностью исключит возможность ложного срабатывания. &lt;br /&gt;
&lt;br /&gt;
Если требуется найти индексы вхождения нескольких образцов, или сравнить две строки &amp;lt;tex&amp;gt;{-}&amp;lt;/tex&amp;gt; выгоднее будет предпосчитать все степени &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а также хеши всех префиксов строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем пример псевдокода, который находит все вхождения строки &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; в строку &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и возвращает массив позиций, откуда начинаются вхождения.&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' rabinKarp (s : '''string''', w : '''string'''):&lt;br /&gt;
    '''vector&amp;lt;int&amp;gt;''' answer&lt;br /&gt;
    '''int''' n = s.length&lt;br /&gt;
    '''int''' m = w.length&lt;br /&gt;
    '''int''' hashS = hash(s[0..m - 1])&lt;br /&gt;
    '''int''' hashW = hash(w[0..m - 1])&lt;br /&gt;
    '''for''' i = 0 '''to''' n - m&lt;br /&gt;
         '''if''' hashS == hashW&lt;br /&gt;
              answer.add(i)&lt;br /&gt;
         hashS = (p * hashS - p&amp;lt;tex&amp;gt;^{m}&amp;lt;/tex&amp;gt; * hash(s[i]) + hash(s[i + m])) '''mod''' r &amp;lt;font color=green&amp;gt;// r — некоторое большое число, p — некоторое просто число&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Новый хеш &amp;lt;tex&amp;gt;hashS&amp;lt;/tex&amp;gt; был получен с помощью быстрого пересчёта. Для сохранения корректности алгоритма нужно считать, что &amp;lt;tex&amp;gt;s[n + 1]&amp;lt;/tex&amp;gt; {{---}} пустой символ.&lt;br /&gt;
&lt;br /&gt;
===Время работы===&lt;br /&gt;
&lt;br /&gt;
Изначальный подсчёт хешей выполняется за &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Каждая итерация выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, В цикле всего &amp;lt;tex&amp;gt;n - m + 1&amp;lt;/tex&amp;gt; итераций.&lt;br /&gt;
&lt;br /&gt;
Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Однако, если требуется исключить ложные срабатывания алгоритма полностью, т.е. придется проверить все полученные позиции вхождения на истинность, то в худшем случае итоговое время работы алгоритма будет &amp;lt;tex&amp;gt;O(n&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Сравнение с другими алгоритмами ==&lt;br /&gt;
Преимущества:&lt;br /&gt;
* Быстрая скорость работы — &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки, &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; — длина образца;&lt;br /&gt;
* Простая и понятная реализация;&lt;br /&gt;
&lt;br /&gt;
Недостатки:&lt;br /&gt;
* Возможно подобрать входные данные так, что количество ложных срабатываний будет недопустимо большим;&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Наивный алгоритм поиска подстроки в строке]]&lt;br /&gt;
*[[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* ''Кормен, Томас Х., Лейзерсон, Чарльз И., Ривест, Рональд Л., Штайн Клиффорд'' '''Алгоритмы: построение и анализ''', 3-е издание. Пер. с англ. — М.:Издательский дом &amp;quot;Вильямс&amp;quot;, 2014. — 1328 с.: ил. — ISBN 978-5-8459-1794-2 (рус.) — страницы 1036–1041.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Поиск подстроки в строке]]&lt;br /&gt;
[[Категория: Хеширование]]&lt;br /&gt;
[[Категория:Точный поиск]]&lt;/div&gt;</summary>
		<author><name>185.102.11.243</name></author>	</entry>

	</feed>