Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа

Материал из Викиконспекты
Версия от 03:58, 17 марта 2011; 192.168.0.2 (обсуждение) (Новая страница: «Алгоритм Рабина — Карпа — это алгоритм поиска строки, который ищет шаблон, то есть подстр…»)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Алгоритм Рабина — Карпа — это алгоритм поиска строки, который ищет шаблон, то есть подстроку, в тексте используя хеширование.

Давайте сначала определимся с методом хеширования.

Выберем полиномиальный хеш - [math]hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])[/math] mod [math]r[/math], где [math]p[/math] - это некоторое простое число, а [math]r[/math] - некоторое большое число, чтобы было меньше коллизий (обычно берётся [math]2^{32}[/math] или [math]2^{64}[/math], чтобы модуль брался автоматически - при переполнении типов;). Заметим, что если 2 строчки имеют одинаковый хэш, то они с большой вероятностью равны.

Научимся переходить от одного хеша к другому за [math]O(1)[/math]:

[math]hash(s[i + 1..i + m - 1]) = hash(s[i..i + m - 1]) - p^{m - 1} s[i][/math].

[math]hash(s[i + 1..i + m]) = p \cdot hash(s[i + 1..i + m]) + s[i + m][/math].

Получается : [math]hash(s[i + 1..i + m]) = p \cdot hash(s[i..i + m - 1]) - p^{m} s[i] + s[i + m][/math].

Теперь к самому алгоритму.

У нас сеть шаблон - [math]p[1..m][/math]. У нас есть строка - [math]s[1..n][/math]. Мы хотим найти все вхождения шаблона в строку.

Давайте посчитаем [math]hash(s[1..m])[/math] и [math]hash(p[1..m])[/math].

И для [math]i \in [1..n - m + 1][/math] считаем [math]hash(s[i..i + m - 1][/math] - сравниваем с [math]hash(p[1..m])[/math]. Если они получаются равными - то мы считаем, что подстрока [math]p[/math] входит в строку [math]s[/math] (начиная с позиции [math]i[/math];).

Следует с предподсчитать - [math]p^{m}[/math].

Псевдо-код:

 1: function RabinKarp(string s[1..n], string p[1..m])
 2:   hp := hash(p[1..m])
 3:   h := hash(s[1..m])ы
 4:   for i from 1 to (n-m+1)
 5:       if h = hp
 6:          add i
 7:       h := p [math]\cdot[/math] h - [math]p^{m}[/math]s[i] + s[i + m]
 8:   return not found

7 строка была получена с помощью быстрого пересчёта хеша. Мы считаем, что [math]s[n + 1][/math] - пустой символ.

Посчитаем время работы.

Изначальный подсчёт хешей - [math]O(m)[/math]. В цикле всего [math]n - m + 1[/math] итераций - каждая выполняется за [math]O(1)[/math]. Итого - [math]O(n + m)[/math].