Поиск наибольшей общей подстроки двух строк с использованием хеширования — различия между версиями
(→Алгоритм) |
(→Алгоритм) |
||
Строка 3: | Строка 3: | ||
==Алгоритм== | ==Алгоритм== | ||
− | Пусть длина наибольшей общей подстроки будет <tex>x</tex>. Заметим, что у строк <tex>s</tex> и <tex>t</tex> обязательно найдется общая подстрока длины <tex>y \in [0 .. x]</tex>, так как в качестве такой строки можно взять префикс наибольшей общей подстроки. Рассмотрим функцию <tex>f : [0 .. \min(|s|, |t|)] \rightarrow \{0, 1\}</tex>, которая для <tex>i</tex> из области определения равна 1, если у строк <tex>s</tex> и <tex>t</tex> есть общая подстрока длины <tex>i</tex>, иначе она равна 0. Согласно замечанию, функция <tex>f</tex> должна по мере возрастания <tex>i</tex> быть равной 1 до некоторого момента, а затем обращаться в 0. Собственно, максимальное значение, при котором функция принимает значение 1, является длиной наибольшей общей подстроки. Таким образом, требуется с помощью бинарного поиска найти это значение. В ходе работы придется проверять наличие общей подстроки заданной длины. Для этого будем использовать хеширование, чтобы улучшить асимптотику алгоритма. | + | Пусть длина наибольшей общей подстроки будет <tex>x</tex>. Заметим, что у строк <tex>s</tex> и <tex>t</tex> обязательно найдется общая подстрока длины <tex>y \in [0 .. x]</tex>, так как в качестве такой строки можно взять префикс наибольшей общей подстроки. Рассмотрим функцию <tex>f : [0 .. \min(|s|, |t|)] \rightarrow \{0, 1\}</tex>, которая для <tex>i</tex> из области определения равна 1, если у строк <tex>s</tex> и <tex>t</tex> есть общая подстрока длины <tex>i</tex>, иначе она равна 0. Согласно замечанию, функция <tex>f</tex> должна по мере возрастания <tex>i</tex> быть равной 1 до некоторого момента, а затем обращаться в 0. Собственно, максимальное значение, при котором функция принимает значение 1, является длиной наибольшей общей подстроки. Таким образом, требуется с помощью бинарного поиска найти это значение. В ходе работы придется проверять наличие общей подстроки заданной длины. Для этого будем использовать хеширование, чтобы улучшить асимптотику алгоритма. Алгоритм является эвристическим и может выдавать неверный ответ, так как совпадение хешей строк не гарантирует их равенство. Алгоритм работает следующим образом: |
− | 1) У строки <tex>s</tex> хешируем подстроки заданной длины и полученные хеши записываем в Set. | + | |
− | 2) У строки <tex>t</tex> хешируем подстроки заданной длины и в случае совпадения хеша с элементом Set выполняем посимвольную проверку на совпадение подстрок, чтобы избежать неверного ответа. | + | 1) У строки <tex>s</tex> хешируем подстроки заданной длины и полученные хеши записываем в Set. |
+ | 2) У строки <tex>t</tex> хешируем подстроки заданной длины и в случае совпадения хеша с элементом Set выполняем посимвольную проверку на совпадение подстрок, чтобы избежать неверного ответа. | ||
+ | |||
Хеширование будем производить так же, как и в [[Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа|алгоритме Рабина-Карпа]]. | Хеширование будем производить так же, как и в [[Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа|алгоритме Рабина-Карпа]]. | ||
Версия 10:39, 21 июня 2012
Постановка задачи
Имеются строки
и такие, что элементы этих строк символы из конечного алфавита . Говорят, что строка является подстрокой строки , если существует такой индекс , что для любого справедливо . Требуется найти такую строку максимальной длины, что является и подстрокой , и подстрокой .Алгоритм
Пусть длина наибольшей общей подстроки будет
. Заметим, что у строк и обязательно найдется общая подстрока длины , так как в качестве такой строки можно взять префикс наибольшей общей подстроки. Рассмотрим функцию , которая для из области определения равна 1, если у строк и есть общая подстрока длины , иначе она равна 0. Согласно замечанию, функция должна по мере возрастания быть равной 1 до некоторого момента, а затем обращаться в 0. Собственно, максимальное значение, при котором функция принимает значение 1, является длиной наибольшей общей подстроки. Таким образом, требуется с помощью бинарного поиска найти это значение. В ходе работы придется проверять наличие общей подстроки заданной длины. Для этого будем использовать хеширование, чтобы улучшить асимптотику алгоритма. Алгоритм является эвристическим и может выдавать неверный ответ, так как совпадение хешей строк не гарантирует их равенство. Алгоритм работает следующим образом:1) У строки
хешируем подстроки заданной длины и полученные хеши записываем в Set. 2) У строки хешируем подстроки заданной длины и в случае совпадения хеша с элементом Set выполняем посимвольную проверку на совпадение подстрок, чтобы избежать неверного ответа.Хеширование будем производить так же, как и в алгоритме Рабина-Карпа.
Псевдокод
findGCS(s, t) n = min(|s|, |t|) left = 0 right = n + 1 while (right - left > 1): val = (left + right) / 2 if (f(val) == 1) left = val else right = val return left
Время работы
Проведем оценку асимптотики времени работы предложенного алгоритма. Посмотрим сколько нам потребуется действий на каждом шаге бинарного поиска. Во-первых, хеширование подстрок строки
и запись их в Set требует шагов. Во-вторых, хеширование подстрок строки и проверка их наличия в Set требует . Значит,на каждый шаг бинарного поиска требуется действий. Заметим, что всего для завершения бинарного поиска потребуется шагов. Следовательно, суммарное время работы алгоритма будет действий.Литература
- Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. — 2-е изд. — М.: Издательский дом «Вильямс», 2007. — С. 1296.