Алгоритм Мейна-Лоренца — различия между версиями
Mariashka (обсуждение | вклад) |
Mariashka (обсуждение | вклад) |
||
Строка 12: | Строка 12: | ||
# Предподсчитаем следующие массивы c помощью [[Z-функция | Z-функции]]: | # Предподсчитаем следующие массивы c помощью [[Z-функция | Z-функции]]: | ||
#* <tex> RP[i] = lcp(v[i \dotsc v.len], \, v) </tex>, то есть наибольший общий префикс строк <tex> v[i \dotsc v.len] </tex> и <tex> v </tex>. Нахождение <tex>lcp(a,\,b[i \dotsc b.len)</tex> можно осуществить следующим образом: вычислим для строки <math> a+'\#'+b </math> [[Z-функция | Z-функцию]]. Очевидно, что в таком случае массивом <tex>lcp</tex> будет массив значений Z-функции, начиная с индекса <tex> a.len + 2 </tex>. | #* <tex> RP[i] = lcp(v[i \dotsc v.len], \, v) </tex>, то есть наибольший общий префикс строк <tex> v[i \dotsc v.len] </tex> и <tex> v </tex>. Нахождение <tex>lcp(a,\,b[i \dotsc b.len)</tex> можно осуществить следующим образом: вычислим для строки <math> a+'\#'+b </math> [[Z-функция | Z-функцию]]. Очевидно, что в таком случае массивом <tex>lcp</tex> будет массив значений Z-функции, начиная с индекса <tex> a.len + 2 </tex>. | ||
− | #* <tex> RS[i] = lcs(v[1 \dotsc i], \, u) </tex>, то есть наибольший общий суффикс строк <tex> v[1 \dotsc i]</tex> и <tex> u </tex> | + | #* <tex> RS[i] = lcs(v[1 \dotsc i], \, u) </tex>, то есть наибольший общий суффикс строк <tex> v[1 \dotsc i]</tex> и <tex> u </tex>. Нахождение <tex>lcs(a,\,b[1 \dotsc i)</tex> можно осуществить следующим образом: вычислим для строки <math> reverse(a)+'\#'+reverse(b) </math> [[Z-функция | Z-функцию]]. Очевидно, что в таком случае массивом <tex>lcs</tex> будет перевернутый массив значений Z-функции, начиная с индекса <tex> a.len + 2 </tex>. |
# Переберем длину повтора <tex> 2p </tex> и будем искать все повторы такой длины: для каждого <tex> p \in [1, \, t.len /2]</tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex> (по формуле, которую докажем позднее). Добавим полученный интервал к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift + u.len, y + shift + u.len) </tex> | # Переберем длину повтора <tex> 2p </tex> и будем искать все повторы такой длины: для каждого <tex> p \in [1, \, t.len /2]</tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex> (по формуле, которую докажем позднее). Добавим полученный интервал к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift + u.len, y + shift + u.len) </tex> | ||
Версия 18:19, 30 апреля 2015
Алгоритм Мейна-Лоренца (англ. Main-Lorentz algorithm) — алгоритм на строках, позволяющий найти все повторы в строке за
Содержание
Алгоритм
Так как повторов строке
, мы не можем хранить их в явном виде. Будем хранить несколько подряд идущих (по индексу конца) повторов одной длины блоками вида , где — это длина повтора, а — промежуток индексов, в каждом из которых заканчивается повтор такой длины. Для каждой длины может быть несколько блоков.Данный алгоритм — это алгоритм типа "разделяй и властвуй": разделим строку пополам, рекурсивно запустимся от каждой половинки — так мы найдем повторы, которые не пересекают границу раздела. Далее рассмотрим процесс нахождения повторов, которые пересекают границу раздела. Их можно разделить на две группы по положению центра повтора: правые и левые.
Нахождение правых повтров
Рассмотрим строку
- Разобьем ее на две строки и .
- Предподсчитаем следующие массивы c помощью Z-функции:
- Z-функцию. Очевидно, что в таком случае массивом будет массив значений Z-функции, начиная с индекса . , то есть наибольший общий префикс строк и . Нахождение можно осуществить следующим образом: вычислим для строки
- Z-функцию. Очевидно, что в таком случае массивом будет перевернутый массив значений Z-функции, начиная с индекса . , то есть наибольший общий суффикс строк и . Нахождение можно осуществить следующим образом: вычислим для строки
- Переберем длину повтора и будем искать все повторы такой длины: для каждого получим интервал индексов конца повтора в строке : (по формуле, которую докажем позднее). Добавим полученный интервал к ответу, учитывая смещение в исходной строке :
Итоговая асимптотика:
Докажем следующее утверждение для нахождения интервала
:Утверждение: |
, где индекс конца повтора в строке . |
Рассмотрим правый повтор Пусть
|
Нахождение левых повтров
Левые повторы находим аналогично правым, кроме вычисления интервала Z-функции массивы:
для заданного и, как следствие, предподсчета. Предподсчитаем с помощью- , то есть наибольший общий префикс строк и
- , то есть наибольший общий суффикс строк и
Докажем следующее утверждение для нахождения интервала
:Утверждение: |
Рассмотрим правый повтор Пусть
|
Асимптотика
Асимптотика алгоритма "разделяй и властвуй", каждый рекурсивный запуск которого линеен относительно длины строки, сортировки слиянием).
из рекурентного соотношения (аналогичное доказательство дляКоличество блоков в ответе также будет
: при каждом рекурсивном запуске добавляется блоков для каждой рассмотренной длины повтора (их количество линейно относительно длины строки), из чего получаем аналогичное рекурентное соотношение .Источники информации
- Main, M., Lorentz, R.J. — An O(n log n) Algorithm for Finding All Repetitions in a String. 1982
- Билл Смит — Методы и алгоритмы вычислений на строках. Пер. с англ.— М.:Издательский дом "Вильямс", 2006. ISBN 5-8459-1081-1