Алгоритм Крочемора — различия между версиями
(→Оптимизация) |
|||
| Строка 95: | Строка 95: | ||
|statement=Предположим, что декомпозиция последовательностей, соответствующих произвольной строке <tex>s[1..n]</tex>, выполняется для уровней <tex>l = 1, 2, \ldots, l^*</tex>, где <tex>l^*</tex> {{---}} наименьший уровень, на котором каждая последовательность содержит единственную позицию. Тогда каждая позиция <tex>i</tex> строки <tex>s</tex> входит в малые последовательности <tex>O(\log n)</tex> раз | |statement=Предположим, что декомпозиция последовательностей, соответствующих произвольной строке <tex>s[1..n]</tex>, выполняется для уровней <tex>l = 1, 2, \ldots, l^*</tex>, где <tex>l^*</tex> {{---}} наименьший уровень, на котором каждая последовательность содержит единственную позицию. Тогда каждая позиция <tex>i</tex> строки <tex>s</tex> входит в малые последовательности <tex>O(\log n)</tex> раз | ||
|proof= | |proof= | ||
| − | Заметим, что если последовательность <tex>c^l_j</tex> разбивается на подпоследовательности <tex>(c^{l+1}_1, c^{l+1}_2, \ldots, c^{l+1}_q)</tex>, то каждая малая последовательность <tex>c^{l+1}_{j'}</tex> удовлетворяет условию <tex>c^{l+1}_{j'} \leqslant {c^{l}_{j} \over 2}</tex>. Другими словами, при <tex>l geqslant 2</tex> каждая малая последовательность не превышает половины размера своей исходной последовательности. Поскольку для <tex>l - 1</tex> начальная малая последовательность может содержать не более n позиций, то из этого следует, что ни одна из позиций не может входить в больше, чем <tex>\log_2(n+1)</tex> малых последовательностей. | + | Заметим, что если последовательность <tex>c^l_j</tex> разбивается на подпоследовательности <tex>(c^{l+1}_1, c^{l+1}_2, \ldots, c^{l+1}_q)</tex>, то каждая малая последовательность <tex>c^{l+1}_{j'}</tex> удовлетворяет условию <tex>c^{l+1}_{j'} \leqslant {c^{l}_{j} \over 2}</tex>. Другими словами, при <tex>l \geqslant 2</tex> каждая малая последовательность не превышает половины размера своей исходной последовательности. Поскольку для <tex>l - 1</tex> начальная малая последовательность может содержать не более n позиций, то из этого следует, что ни одна из позиций не может входить в больше, чем <tex>\log_2(n+1)</tex> малых последовательностей. |
}} | }} | ||
Версия 16:39, 12 июня 2014
| Определение: |
| Тандемным повтором (англ. "tandem repeat") в строке называются два вхождения какой-либо подстроки подряд. Иными словами, тандемный повтор описывается парой индексов такими, что подстрока — это две одинаковые строки, записанные подряд |
Алгоритм Крочемора (англ. "crochemore algorithm") — алгоритм на строках, позволяющий найти все тандемные повторы в строке за
Алгоритм
Разобьем описание алгоритма на две части: сначала покажем упрощенный алгоритм, работающий за , а затем попытаемся его оптимизировать до
Упрощенный алгоритм
Рассмотрим следующую строку Фиббоначи:
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
| a | b | a | a | b | a | b | a | a | b | a | a | b |
Будем вычислять все повторяющиеся подстроки длины , где . Зная эти данные, мы автоматически находим все тандемные повторы.
Предположим, что в строке вычислены последовательности позиций, в которых встречаются одинаковые символы:
| <1, 3, 4, 6, 8, 9, 11, 12> | <2, 5, 7, 10, 13> | |
| a | b |
Если нам заранее известен алфавит и он индексирован, то мы можем выполнить данное вычисление за .
Далее для мы хотим найти все повторяющиеся подстроки длины . Поскольку повторяющиеся подстроки длины будут иметь общий префикс длиной , то вычисления уровня должны привести к последовательностям, которые будут подпоследовательностями последовательностей, вычисленных на уровне . Другими словами, разбиение на уровне — декомпозиция разбиения на уровне :
| Последовательная декомпозиция строки | |||||
|---|---|---|---|---|---|
| <1, 4, 6, 9, 12> | <3, 8, 11> | <2, 5, 7, 10> | <13> | ||
| ab | aa | ba | b$ | ||
| <1, 4, 6, 9> | <12> | <3, 8, 11> | <2, 7, 10> | <5> | |
| aba | aa$ | aab | baa | bab | |
| <1, 6, 9> | <4> | <3, 8> | <11> | <2, 7, 10> | |
| abaa | abab | aaba | aab$ | baab | |
| <1, 6, 9> | <3> | <8> | <2, 7> | <10> | |
| abaab | aabab | aabaa | baaba | baab$ | |
| <1, 6> | <9> | <2> | <7> | ||
| abaaba | abaab$ | baabab | baabaa | ||
| <1> | <6> | ||||
| abaabab | abaabaa | ||||
Если реализовывать процесс декомпозиции "наивно", то поучаем сложность
Оптимизация
Декомпозицию каждой последовательности можно получить косвенным путем, а не путем прямых вычислений. Идея такого подхода состоит в следующем: на каждом уровне выполняется непосредственная декомпозиция каждой последовательности . Более точно, если , то необходимо проверить совпадение букв , и, если какие-либо пары букв и равны, то и помещаются в одну и ту же последовательность на уровне .
Заметим, что декомпозицию можно выполнить, основываясь не на разбиваемой последовательности, а на последовательностях, относительно которых будут разбиваться другие последовательности.
Для каждой позиции известно, что подстрока (длиной ) относится к некоторой последовательности на уровне . Поскольку последовательность соответствует уникальной подстроке строки , то каждая такая последовательность должна формироваться из тех же позиций последовательности , которые определяют класс эквивалентности
.
Таким образом, декомпозицию на уровне можно выполнить косвенным путем, рассматривая каждую последовательность уровня с позиции, находящейся на левее от начальной позиции этой последовательности.
| Лемма: |
В каждом наборе последовательностей, порожденных одной последовательностью уровня , всегда можно исключить использование одной из них для декомпозиции последовательностей на уровне |
| Доказательство: |
| TBA |
| Определение: |
| В декомпозиции последовательности на последовательности назовем одну последовательность с наибольшим количеством элементов большой, а остальные последовательности - малыми. Для все последовательности будем считать малыми. |
| Лемма: |
Предположим, что декомпозиция последовательностей, соответствующих произвольной строке , выполняется для уровней , где — наименьший уровень, на котором каждая последовательность содержит единственную позицию. Тогда каждая позиция строки входит в малые последовательности раз |
| Доказательство: |
| Заметим, что если последовательность разбивается на подпоследовательности , то каждая малая последовательность удовлетворяет условию . Другими словами, при каждая малая последовательность не превышает половины размера своей исходной последовательности. Поскольку для начальная малая последовательность может содержать не более n позиций, то из этого следует, что ни одна из позиций не может входить в больше, чем малых последовательностей. |
Поскольку строка содержит позиций, то из предыдущей леммы следует, что всего в малых последовательностях на всех уровнях содержится позиций. Таким образом, если время обработки последовательностей на каждом уровне пропорционально количеству элементов в малых последовательностях этого уровня, то полный процесс декомпозиции будет выполнен за , чего мы и хотели получить.
Псевдокод
crochemore()
1
Вычислим все последовательности на уровне 1 и пометим их как малые
while малая последовательность на уровне :
out кратные строки с периодом l
Вычислим декомпозицию последовательностей уровня , используя только малые последовательности
l++
Найдем малые последовательности на уровне
Реализация
Классифицируем основные структуры данных в соответствии с их основными функциями:
- Массив seq — содержит индекс текущей последовательности, которой принадлежит позиция
- Массив seq_list — содержит указатель на двусвязный список позиций, принадлежащих последовательности с индексом и расположенных в порядке их возрастания
- Массив seq_size — равно количеству позиций в последовательности с индексом , т.е. количеству последовательностей в списке, на который указывает
- Стек index_stack — стек неиспользованных индексов последовательностей
Источники
- Билл Смит Методы и алгоритмы вычислений на строках. Пер. с англ.— М.:Издательский дом "Вильямс", 2006. ISBN 5-8459-1081-1
- E-maxx — Поиск всех тандемных повторов в строке. Алгоритм Мейна-Лоренца