Участница:Mariashka — различия между версиями
Mariashka (обсуждение | вклад) |
Mariashka (обсуждение | вклад) |
||
| Строка 6: | Строка 6: | ||
== Алгоритм == | == Алгоритм == | ||
| − | Данный алгоритм - это алгоритм "разделяй и властвуй": | + | Данный алгоритм {{---}} это алгоритм "разделяй и властвуй": |
# Разделим строку пополам | # Разделим строку пополам | ||
# Заметим, что повторы делятся на две группы: пересекающие и не пересекающие границу раздела | # Заметим, что повторы делятся на две группы: пересекающие и не пересекающие границу раздела | ||
| − | # Рекурсивно запустимся от каждой половинки - так мы найдем повторы, которые не пересекают границу раздела | + | # Рекурсивно запустимся от каждой половинки {{---}} так мы найдем повторы, которые не пересекают границу раздела |
# Нахождение повторов, которые пересекают границу раздела | # Нахождение повторов, которые пересекают границу раздела | ||
Повторы, пересекающие границу раздела, можно разделить на две группы по положению центра повтора. | Повторы, пересекающие границу раздела, можно разделить на две группы по положению центра повтора. | ||
| − | Так как повторов строке <tex> \Omega(n^2)</tex>, мы не можем хранить их в явном виде. Будем хранить повторы блоками вида <tex>(length, first, last)</tex>, где <tex> length </tex> - это длина повтора, а <tex> [first, last] </tex> - промежуток индексов, в которых заканчиваются повторы такой длины. | + | Так как повторов строке <tex> \Omega(n^2)</tex>, мы не можем хранить их в явном виде. Будем хранить повторы блоками вида <tex>(length, first, last)</tex>, где <tex> length </tex> {{---}} это длина повтора, а <tex> [first, last] </tex> {{---}} промежуток индексов, в которых заканчиваются повторы такой длины. |
=== Нахождение правых повтров === | === Нахождение правых повтров === | ||
| − | Рассмотрим строку <tex>t = uv</tex>, пусть начало <tex>t</tex> в исходной строке <tex>s</tex> - <tex>shift</tex> | + | Рассмотрим строку <tex>t = uv</tex>, пусть начало <tex>t</tex> в исходной строке <tex>s</tex> {{---}} <tex>shift</tex> |
# Предподсчитаем следующие массивы: | # Предподсчитаем следующие массивы: | ||
| − | ## <tex> RP[i] = lcp(v[i..v.len], v) </tex>, где <tex> lcp </tex> - наибольший общий префикс | + | ## <tex> RP[i] = lcp(v[i..v.len], v) </tex>, где <tex> lcp </tex> {{---}} наибольший общий префикс |
| − | ## <tex> RS[i] = lcs(v[1..i], u) </tex>, где <tex> lcs </tex> - наибольший общий суффикс | + | ## <tex> RS[i] = lcs(v[1..i], u) </tex>, где <tex> lcs </tex> {{---}} наибольший общий суффикс |
# Переберем длину повтора <tex> 2p </tex>. Для каждого <tex> p </tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex>. | # Переберем длину повтора <tex> 2p </tex>. Для каждого <tex> p </tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex>. | ||
| − | # Добавим к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift, y + shift) </tex> | + | # Добавим к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift + u.len, y + shift + u.len) </tex> |
Докажем следующее утверждение для нахождения интервала <tex> [x, y] </tex>: | Докажем следующее утверждение для нахождения интервала <tex> [x, y] </tex>: | ||
| Строка 33: | Строка 33: | ||
=== Нахождение левых повтров === | === Нахождение левых повтров === | ||
| − | Рассмотрим строку <tex>t = uv</tex>, пусть начало <tex>t</tex> в исходной строке <tex>s</tex> - <tex>shift</tex> | + | Рассмотрим строку <tex>t = uv</tex>, пусть начало <tex>t</tex> в исходной строке <tex>s</tex> {{---}} <tex>shift</tex> |
# Предподсчитаем следующие массивы: | # Предподсчитаем следующие массивы: | ||
| − | ## <tex> LP[i] = lcp(u[i..u.len], u) </tex>, где <tex> lcp </tex> - наибольший общий префикс | + | ## <tex> LP[i] = lcp(u[i..u.len], u) </tex>, где <tex> lcp </tex> {{---}} наибольший общий префикс |
| − | ## <tex> LS[i] = lcs(u[1..i], u) </tex>, где <tex> lcs </tex> - наибольший общий суффикс | + | ## <tex> LS[i] = lcs(u[1..i], u) </tex>, где <tex> lcs </tex> {{---}} наибольший общий суффикс |
# Переберем длину повтора <tex> 2p </tex>. Для каждого <tex> p </tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex>. | # Переберем длину повтора <tex> 2p </tex>. Для каждого <tex> p </tex> получим интервал индексов конца повтора в строке <tex> v </tex>: <tex> [x, y] </tex>. | ||
| − | # Добавим к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift, y + shift) </tex> | + | # Добавим к ответу, учитывая смещение в исходной строке <tex> s </tex> : <tex>(2p, x + shift + u.len, y + shift + u.len) </tex> |
Докажем следующее утверждение для нахождения интервала <tex> [x, y] </tex>: | Докажем следующее утверждение для нахождения интервала <tex> [x, y] </tex>: | ||
| Строка 48: | Строка 48: | ||
}} | }} | ||
| − | == | + | === Результат === |
| + | |||
| + | # Рекурсивно найдем повторы, полностью лежащие в одной из половинок | ||
| + | # Вычислим LP, LS, RP, RS для t с помощью z-функции: <tex> O(n) </tex> | ||
| + | # Найдем правые и левые повторы, как изложено выше: <tex> O(n) </tex> | ||
| + | |||
| + | == Асимптотика == | ||
| + | Ассимптотика алгоритма "разделяй и властвуй", каждый рекурсивный запуск которого линеен относительно длины строки, <tex> O(n \log n) </tex>. | ||
| + | |||
| + | Количество блоков в ответе также будет <tex> O(n \log n) </tex>, так как при каждом рекрсивном запуске добавляется <tex> O(1) </tex> блоков для каждой рассмотренной длины повтора, а их количество линейно относительно длины строки. | ||
Версия 23:59, 26 апреля 2015
| Определение: |
| Повтором (англ. repeatition) называется непустая строка вида |
Алгоритм Мейна-Лоренца (англ. Main-Lorentz algorithm) — алгоритм на строках, позволяющий найти все повторы в строке за
Содержание
Алгоритм
Данный алгоритм — это алгоритм "разделяй и властвуй":
- Разделим строку пополам
- Заметим, что повторы делятся на две группы: пересекающие и не пересекающие границу раздела
- Рекурсивно запустимся от каждой половинки — так мы найдем повторы, которые не пересекают границу раздела
- Нахождение повторов, которые пересекают границу раздела
Повторы, пересекающие границу раздела, можно разделить на две группы по положению центра повтора.
Так как повторов строке , мы не можем хранить их в явном виде. Будем хранить повторы блоками вида , где — это длина повтора, а — промежуток индексов, в которых заканчиваются повторы такой длины.
Нахождение правых повтров
Рассмотрим строку , пусть начало в исходной строке —
- Предподсчитаем следующие массивы:
- , где — наибольший общий префикс
- , где — наибольший общий суффикс
- Переберем длину повтора . Для каждого получим интервал индексов конца повтора в строке : .
- Добавим к ответу, учитывая смещение в исходной строке :
Докажем следующее утверждение для нахождения интервала :
| Утверждение: |
| TODO |
Нахождение левых повтров
Рассмотрим строку , пусть начало в исходной строке —
- Предподсчитаем следующие массивы:
- , где — наибольший общий префикс
- , где — наибольший общий суффикс
- Переберем длину повтора . Для каждого получим интервал индексов конца повтора в строке : .
- Добавим к ответу, учитывая смещение в исходной строке :
Докажем следующее утверждение для нахождения интервала :
| Утверждение: |
| TODO |
Результат
- Рекурсивно найдем повторы, полностью лежащие в одной из половинок
- Вычислим LP, LS, RP, RS для t с помощью z-функции:
- Найдем правые и левые повторы, как изложено выше:
Асимптотика
Ассимптотика алгоритма "разделяй и властвуй", каждый рекурсивный запуск которого линеен относительно длины строки, .
Количество блоков в ответе также будет , так как при каждом рекрсивном запуске добавляется блоков для каждой рассмотренной длины повтора, а их количество линейно относительно длины строки.