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

Материал из Викиконспекты
Перейти к: навигация, поиск
(Псевдокод)
Строка 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 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны.
  
 
При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за <tex>O(1)</tex>:
 
При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за <tex>O(1)</tex>:
Строка 15: Строка 15:
 
==Алгоритм==
 
==Алгоритм==
  
Есть шаблон - <tex>p[1..m]</tex> и строка - <tex>s[1..n]</tex>. Нужно найти все вхождения шаблона в строку.
+
Есть шаблон {{---}} <tex>p[1..m]</tex> и строка {{---}} <tex>s[1..n]</tex>. Нужно найти все вхождения шаблона в строку.
  
 
В начале вычисляются <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>p</tex> входит в строку <tex>s</tex> (начиная с позиции <tex>i</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>.
Строка 36: Строка 36:
 
             '''return''' answer
 
             '''return''' answer
  
Новый хеш h был получен с помощью быстрого пересчёта. Следует считать, что s[n + 1] - пустой символ.
+
Новый хеш <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>.
  
 
== Литература ==
 
== Литература ==
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. 2-е изд. М.: Издательский дом «Вильямс», 2007. С. 1296.
+
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296.

Версия 13:40, 4 апреля 2012

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

Метод хеширования

Следует использовать полиномиальный хеш — [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 - 1]) + 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].

Псевдокод

 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[math]^{m}[/math] * hash(s[i]) + hash(s[i + m)
      if answer.size() == 0
           return not found
      else
           return answer

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

Время работы

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

Литература

Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.