Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа — различия между версиями
(→Алгоритм) |
Vasin (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
Алгоритм Рабина — Карпа — это алгоритм поиска подстроки в строке, используя хеширование. | Алгоритм Рабина — Карпа — это алгоритм поиска подстроки в строке, используя хеширование. | ||
− | + | ==Метод хеширования== | |
Выберем полиномиальный хеш - <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])</tex> mod <tex>r</tex>, где <tex>p</tex> - это некоторое простое число, а <tex>r</tex> - некоторое большое число, чтобы было меньше коллизий (обычно берётся <tex>2^{32}</tex> или <tex>2^{64}</tex>, чтобы модуль брался автоматически - при переполнении типов;). Заметим, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны. | Выберем полиномиальный хеш - <tex>hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])</tex> mod <tex>r</tex>, где <tex>p</tex> - это некоторое простое число, а <tex>r</tex> - некоторое большое число, чтобы было меньше коллизий (обычно берётся <tex>2^{32}</tex> или <tex>2^{64}</tex>, чтобы модуль брался автоматически - при переполнении типов;). Заметим, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны. | ||
Строка 13: | Строка 13: | ||
Получается : <tex>hash(s[i + 1..i + m]) = p \cdot hash(s[i..i + m - 1]) - p^{m} s[i] + s[i + m]</tex>. | Получается : <tex>hash(s[i + 1..i + m]) = p \cdot hash(s[i..i + m - 1]) - p^{m} s[i] + s[i + m]</tex>. | ||
− | + | ==Алгоритм== | |
У нас есть шаблон - <tex>p[1..m]</tex>. У нас есть строка - <tex>s[1..n]</tex>. Мы хотим найти все вхождения шаблона в строку. | У нас есть шаблон - <tex>p[1..m]</tex>. У нас есть строка - <tex>s[1..n]</tex>. Мы хотим найти все вхождения шаблона в строку. | ||
Строка 23: | Строка 23: | ||
Следует предподсчитать <tex>p^{m}</tex>. | Следует предподсчитать <tex>p^{m}</tex>. | ||
− | + | ==Псевдокод== | |
− | ''' | + | '''RabinKarp''' ('''string''' <tex>s[1..n]</tex>, '''string''' <tex>p[1..m]</tex>) |
− | + | <tex>hp \leftarrow hash(p[1..m])</tex> | |
− | + | <tex>h \leftarrow hash(s[1..m])</tex> | |
− | + | '''for''' <tex>i \leftarrow 1</tex> '''to''' <tex>n - m + 1</tex> | |
− | + | '''if''' <tex>h = hp</tex> | |
− | + | <tex>answer.add(i)</tex> | |
− | + | <tex>h \leftarrow p \cdot h - p^{m} \cdot hash(s[i]) + hash(s[i + m])</tex> | |
− | + | '''if''' <tex>ans.size = 0</tex> | |
− | + | '''return''' <tex>not</tex> <tex>found</tex> | |
− | + | '''else''' | |
− | + | '''return''' <tex>answer</tex> | |
− | + | Новый хеш <tex>h</tex> был получен с помощью быстрого пересчёта. Мы считаем, что <tex>s[n + 1]</tex> - пустой символ. | |
− | + | ==Время работы== | |
Изначальный подсчёт хешей - <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>. |
Версия 22:02, 24 марта 2012
Алгоритм Рабина — Карпа — это алгоритм поиска подстроки в строке, используя хеширование.
Метод хеширования
Выберем полиномиальный хеш -
mod , где - это некоторое простое число, а - некоторое большое число, чтобы было меньше коллизий (обычно берётся или , чтобы модуль брался автоматически - при переполнении типов;). Заметим, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны.Давайте научимся при удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки за
:.
.
Получается :
.Алгоритм
У нас есть шаблон -
. У нас есть строка - . Мы хотим найти все вхождения шаблона в строку.Давайте посчитаем
и .И для
считаем - сравниваем с . Если они получаются равными - то мы считаем, что подстрока входит в строку (начиная с позиции ;) или мы проверяем, что подстрока является шаблоном, для этого выберем случайные символы из строк и сравним их.Следует предподсчитать
.Псевдокод
RabinKarp (string, string ) for to if if return else return
Новый хеш
был получен с помощью быстрого пересчёта. Мы считаем, что - пустой символ.Время работы
Изначальный подсчёт хешей -
. В цикле всего итераций - каждая выполняется за . Итого - .Литература
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.