Алгоритм Манакера — различия между версиями
 (→См. также)  | 
				 (→Источники информации)  | 
				||
| Строка 79: | Строка 79: | ||
== Источники информации ==  | == Источники информации ==  | ||
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]  | *[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]  | ||
| + | * [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]  | ||
| + | *[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]  | ||
[[Категория: Алгоритмы и структуры данных]]  | [[Категория: Алгоритмы и структуры данных]]  | ||
[[Категория: Поиск подстроки в строке]]  | [[Категория: Поиск подстроки в строке]]  | ||
Версия 22:35, 17 марта 2016
| Задача: | 
| Пусть дана строка . Требуется найти — длина наибольшего палиндрома нечетной длины с центром в позиции и — аналогично для палиндромов четной длины для всех от 1 до . | 
Содержание
Наивный алгоритм
Идея
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции , будем на каждом шаге увеличивать длину палиндрома с центром в и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за
Псевдокод
// — исходная строка // — массивы для записи ответа for i = 1 to n d1[i] = 1 while i - d1[i] > 0 and i + d1[i] <= n and s[i - d1[i]] == s[i + d1[i]] d1[i]++ d2[i] = 0 while i - d2[i] - 1 > 0 and i + d2[i] <= n and s[i - d2[i] - 1] == s[i + d2[i]] d2[i]++
Алгоритм Манакера
Идея
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. Будем поддерживать границы самого правого из найденных палиндромов — . Итак, пусть мы хотим вычислить — т.е. длину наибольшего палиндрома с центром в позиции . При этом все предыдущие значения в массиве уже посчитаны. Возможны два случая:
- , т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции .
 - . Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома . Поскольку и — симметричные позиции, то мы можем утверждать, . Однако надо не забыть про один граничный случай: что если выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет, то необходимо ограничить значение следующим образом: . После этого запустим наивный алгоритм, который будет увеличивать значение , пока это возможно.
 
После каждого шага важно не забывать обновлять значения
Заметим, что массив считается аналогичным образом, нужно лишь немного изменить индексы.
Псевдокод
Приведем код, который вычисляет значения массива :
//  — исходная строка
int l = 0
int r = -1
for i = 1 to n
  int k = 0
  if i <= r
     k = min(r - i, d[r - i + l])
  while i + k + 1 <= n and i - k - 1 > 0 and s[i + k + 1] == s[i - k - 1]
     k++
   d1[i] = k
   if i + k > r
     l = i - k
     r = i + k
Вычисление значений массива :
//  — исходная строка
int l = 0
int r = -1
for i = 1 to n
  int k = 0
  if i <= r
     k = min(r - i + 1, d[r - i + l + 1])
  while i + k <= n and i - k - 1 > 0 and s[i + k] == s[i - k - 1]
     k++
   d2[i] = k
   if i + k - 1 > r
     l = i - k
     r = i + k - 1
Оценка сложности
Внешний цикл в приведенном алгоритме выполняется ровно раз, где — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению на . Действительно, возможны следующие случаи:
- , т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение хотя бы на
 -  . Здесь опять два случая:
- , но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет
 - , тогда каждая итерация вложенного цикла приведет к увеличению хотя бы на .
 
 
Т.к. значение не может увеличиваться более раз, то описанный выше алгоритм работает за линейное время.
