<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.158.37&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.158.37&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.66.158.37"/>
		<updated>2026-06-22T23:36:54Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9A%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D0%BF%D0%BE%D0%B4%D0%BF%D0%B0%D0%BB%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC%D0%BE%D0%B2_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5&amp;diff=53375</id>
		<title>Количество подпалиндромов в строке</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9A%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D0%BF%D0%BE%D0%B4%D0%BF%D0%B0%D0%BB%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC%D0%BE%D0%B2_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5&amp;diff=53375"/>
				<updated>2016-04-18T20:00:37Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: Перенаправление на Алгоритм Манакера&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#перенаправление [[Алгоритм Манакера]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53374</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53374"/>
				<updated>2016-04-18T19:58:07Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#palindrome | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
=== Идея ===&lt;br /&gt;
Рассмотрим сначала задачу поиска палиндромов нечетной длины. Центром строки нечетной длины назовем символ под индексом &amp;lt;tex&amp;gt;\left\lfloor \dfrac{|t|}{2}\right\rfloor&amp;lt;/tex&amp;gt;. Для каждой позиции в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; найдем длину наибольшего палиндрома с центром в этой позиции. Очевидно, что если строка &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; является палиндромом, то строка полученная вычеркиванием первого и последнего символа из &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; также является палиндромом, поэтому длину палиндрома можно искать [[Целочисленный_двоичный_поиск | бинарным поиском]]. Проверить совпадение левой и правой половины можно выполнить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, используя метод хеширования. &lt;br /&gt;
&lt;br /&gt;
Для палиндромов четной длины алгоритм такой же. Центр строки четной длины {{---}} некий мнимый элемент между &amp;lt;tex&amp;gt;\dfrac{|t|}{2} - 1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\dfrac{|t|}{2}&amp;lt;/tex&amp;gt;. Только требуется проверять вторую строку со сдвигом на единицу. Следует заметить, что мы не посчитаем никакой палиндром дважды из-за четности-нечетности длин палиндромов.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
 '''int''' binarySearch(s : '''string''', center, shift : '''int'''):&lt;br /&gt;
     ''&amp;lt;font color=green&amp;gt;//shift = 0 при поиске палиндрома нечетной длины, иначе shift = 1&amp;lt;/font&amp;gt;''&lt;br /&gt;
     '''int''' l = -1, r = min(center, s.length - center + shift), m = 0&lt;br /&gt;
     '''while''' r - l != 1&lt;br /&gt;
         m = l + (r - l) / 2&lt;br /&gt;
         ''&amp;lt;font color=green&amp;gt;//reversed_hash возвращает хэш развернутой строки s&amp;lt;/font&amp;gt;''&lt;br /&gt;
         '''if''' hash(s[center - m..center]) == reversed_hash(s[center + shift..center + shift + m])&lt;br /&gt;
             l = m&lt;br /&gt;
         '''else'''&lt;br /&gt;
             r = m&lt;br /&gt;
     '''return''' r&lt;br /&gt;
&lt;br /&gt;
 '''int''' palindromesCount(s : '''string'''):&lt;br /&gt;
     '''int''' ans = 0&lt;br /&gt;
     '''for''' i = 0 '''to''' s.length&lt;br /&gt;
         ans += binarySearch(s, i, 0) + binarySearch(s, i, 1)&lt;br /&gt;
     '''return''' ans&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
Изначальный подсчет хешей производится за &amp;lt;tex&amp;gt;O(|s|)&amp;lt;/tex&amp;gt;. Каждая итерация будет выполняться за &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt;, всего итераций {{---}} &amp;lt;tex&amp;gt;|s|&amp;lt;/tex&amp;gt;. Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(|s|+|s|\cdot \log(|s|)) = O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Избавление от коллизий ===&lt;br /&gt;
У хешей есть один недостаток {{---}} коллизии: можно подобрать входные данные так, что хеши разных строк будут совпадать. Абсолютно точно проверить две подстроки на совпадение можно с помощью [[Суффиксный массив | суффиксного массива]], но с дополнительной памятью &amp;lt;tex&amp;gt;O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;. Для этого построим суффиксный массив для строки &amp;lt;tex&amp;gt;s + \# + reverse(s)&amp;lt;/tex&amp;gt;, при этом сохраним промежуточные результаты классов эквивалентности &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;. Пусть нам требуется проверить на совпадение подстроки &amp;lt;tex&amp;gt;s[i..i + l]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[j..j + l]&amp;lt;/tex&amp;gt;. Разобьем каждую нашу строку на две пересекающиеся подстроки длиной &amp;lt;tex&amp;gt;2^k&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;k = \lfloor \log{l} \rfloor&amp;lt;/tex&amp;gt;. Тогда наши строки совпадают, если &amp;lt;tex&amp;gt;c[k][i] = c[k][j]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;c[k][i + l - 2^k] = c[k][j + l - 2^k]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Итоговая асимптотика алгоритма: предподсчет за построение суффиксного массива и &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt; на запрос, если предподсчитать все &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
* [[Суффиксный массив]]&lt;br /&gt;
* [[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
* [https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
* [http://e-maxx.ru/algo/suffix_array#5 MAXimal :: algo :: Суффиксный массив]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Основные определения. Простые комбинаторные свойства слов]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53373</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53373"/>
				<updated>2016-04-18T19:57:35Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* См. также */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#palindrome | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
=== Идея ===&lt;br /&gt;
Рассмотрим сначала задачу поиска палиндромов нечетной длины. Центром строки нечетной длины назовем символ под индексом &amp;lt;tex&amp;gt;\left\lfloor \dfrac{|t|}{2}\right\rfloor&amp;lt;/tex&amp;gt;. Для каждой позиции в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; найдем длину наибольшего палиндрома с центром в этой позиции. Очевидно, что если строка &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; является палиндромом, то строка полученная вычеркиванием первого и последнего символа из &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; также является палиндромом, поэтому длину палиндрома можно искать [[Целочисленный_двоичный_поиск | бинарным поиском]]. Проверить совпадение левой и правой половины можно выполнить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, используя метод хеширования. &lt;br /&gt;
&lt;br /&gt;
Для палиндромов четной длины алгоритм такой же. Центр строки четной длины {{---}} некий мнимый элемент между &amp;lt;tex&amp;gt;\dfrac{|t|}{2} - 1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\dfrac{|t|}{2}&amp;lt;/tex&amp;gt;. Только требуется проверять вторую строку со сдвигом на единицу. Следует заметить, что мы не посчитаем никакой палиндром дважды из-за четности-нечетности длин палиндромов.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
 '''int''' binarySearch(s : '''string''', center, shift : '''int'''):&lt;br /&gt;
     ''&amp;lt;font color=green&amp;gt;//shift = 0 при поиске палиндрома нечетной длины, иначе shift = 1&amp;lt;/font&amp;gt;''&lt;br /&gt;
     '''int''' l = -1, r = min(center, s.length - center + shift), m = 0&lt;br /&gt;
     '''while''' r - l != 1&lt;br /&gt;
         m = l + (r - l) / 2&lt;br /&gt;
         ''&amp;lt;font color=green&amp;gt;//reversed_hash возвращает хэш развернутой строки s&amp;lt;/font&amp;gt;''&lt;br /&gt;
         '''if''' hash(s[center - m..center]) == reversed_hash(s[center + shift..center + shift + m])&lt;br /&gt;
             l = m&lt;br /&gt;
         '''else'''&lt;br /&gt;
             r = m&lt;br /&gt;
     '''return''' r&lt;br /&gt;
&lt;br /&gt;
 '''int''' palindromesCount(s : '''string'''):&lt;br /&gt;
     '''int''' ans = 0&lt;br /&gt;
     '''for''' i = 0 '''to''' s.length&lt;br /&gt;
         ans += binarySearch(s, i, 0) + binarySearch(s, i, 1)&lt;br /&gt;
     '''return''' ans&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
Изначальный подсчет хешей производится за &amp;lt;tex&amp;gt;O(|s|)&amp;lt;/tex&amp;gt;. Каждая итерация будет выполняться за &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt;, всего итераций {{---}} &amp;lt;tex&amp;gt;|s|&amp;lt;/tex&amp;gt;. Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(|s|+|s|\cdot \log(|s|)) = O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Избавление от коллизий ===&lt;br /&gt;
У хешей есть один недостаток {{---}} коллизии: можно подобрать входные данные так, что хеши разных строк будут совпадать. Абсолютно точно проверить две подстроки на совпадение можно с помощью [[Суффиксный массив | суффиксного массива]], но с дополнительной памятью &amp;lt;tex&amp;gt;O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;. Для этого построим суффиксный массив для строки &amp;lt;tex&amp;gt;s + \# + reverse(s)&amp;lt;/tex&amp;gt;, при этом сохраним промежуточные результаты классов эквивалентности &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;. Пусть нам требуется проверить на совпадение подстроки &amp;lt;tex&amp;gt;s[i..i + l]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[j..j + l]&amp;lt;/tex&amp;gt;. Разобьем каждую нашу строку на две пересекающиеся подстроки длиной &amp;lt;tex&amp;gt;2^k&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;k = \lfloor \log{l} \rfloor&amp;lt;/tex&amp;gt;. Тогда наши строки совпадают, если &amp;lt;tex&amp;gt;c[k][i] = c[k][j]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;c[k][i + l - 2^k] = c[k][j + l - 2^k]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Итоговая асимптотика алгоритма: предподсчет за построение суффиксного массива и &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt; на запрос, если предподсчитать все &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
* [[Суффиксный массив]]&lt;br /&gt;
* [[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Основные определения. Простые комбинаторные свойства слов]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53372</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53372"/>
				<updated>2016-04-18T19:56:24Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#palindrome | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
=== Идея ===&lt;br /&gt;
Рассмотрим сначала задачу поиска палиндромов нечетной длины. Центром строки нечетной длины назовем символ под индексом &amp;lt;tex&amp;gt;\left\lfloor \dfrac{|t|}{2}\right\rfloor&amp;lt;/tex&amp;gt;. Для каждой позиции в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; найдем длину наибольшего палиндрома с центром в этой позиции. Очевидно, что если строка &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; является палиндромом, то строка полученная вычеркиванием первого и последнего символа из &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; также является палиндромом, поэтому длину палиндрома можно искать [[Целочисленный_двоичный_поиск | бинарным поиском]]. Проверить совпадение левой и правой половины можно выполнить за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, используя метод хеширования. &lt;br /&gt;
&lt;br /&gt;
Для палиндромов четной длины алгоритм такой же. Центр строки четной длины {{---}} некий мнимый элемент между &amp;lt;tex&amp;gt;\dfrac{|t|}{2} - 1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\dfrac{|t|}{2}&amp;lt;/tex&amp;gt;. Только требуется проверять вторую строку со сдвигом на единицу. Следует заметить, что мы не посчитаем никакой палиндром дважды из-за четности-нечетности длин палиндромов.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
 '''int''' binarySearch(s : '''string''', center, shift : '''int'''):&lt;br /&gt;
     ''&amp;lt;font color=green&amp;gt;//shift = 0 при поиске палиндрома нечетной длины, иначе shift = 1&amp;lt;/font&amp;gt;''&lt;br /&gt;
     '''int''' l = -1, r = min(center, s.length - center + shift), m = 0&lt;br /&gt;
     '''while''' r - l != 1&lt;br /&gt;
         m = l + (r - l) / 2&lt;br /&gt;
         ''&amp;lt;font color=green&amp;gt;//reversed_hash возвращает хэш развернутой строки s&amp;lt;/font&amp;gt;''&lt;br /&gt;
         '''if''' hash(s[center - m..center]) == reversed_hash(s[center + shift..center + shift + m])&lt;br /&gt;
             l = m&lt;br /&gt;
         '''else'''&lt;br /&gt;
             r = m&lt;br /&gt;
     '''return''' r&lt;br /&gt;
&lt;br /&gt;
 '''int''' palindromesCount(s : '''string'''):&lt;br /&gt;
     '''int''' ans = 0&lt;br /&gt;
     '''for''' i = 0 '''to''' s.length&lt;br /&gt;
         ans += binarySearch(s, i, 0) + binarySearch(s, i, 1)&lt;br /&gt;
     '''return''' ans&lt;br /&gt;
&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
Изначальный подсчет хешей производится за &amp;lt;tex&amp;gt;O(|s|)&amp;lt;/tex&amp;gt;. Каждая итерация будет выполняться за &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt;, всего итераций {{---}} &amp;lt;tex&amp;gt;|s|&amp;lt;/tex&amp;gt;. Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(|s|+|s|\cdot \log(|s|)) = O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Избавление от коллизий ===&lt;br /&gt;
У хешей есть один недостаток {{---}} коллизии: можно подобрать входные данные так, что хеши разных строк будут совпадать. Абсолютно точно проверить две подстроки на совпадение можно с помощью [[Суффиксный массив | суффиксного массива]], но с дополнительной памятью &amp;lt;tex&amp;gt;O(|s|\cdot \log(|s|))&amp;lt;/tex&amp;gt;. Для этого построим суффиксный массив для строки &amp;lt;tex&amp;gt;s + \# + reverse(s)&amp;lt;/tex&amp;gt;, при этом сохраним промежуточные результаты классов эквивалентности &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;. Пусть нам требуется проверить на совпадение подстроки &amp;lt;tex&amp;gt;s[i..i + l]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[j..j + l]&amp;lt;/tex&amp;gt;. Разобьем каждую нашу строку на две пересекающиеся подстроки длиной &amp;lt;tex&amp;gt;2^k&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;k = \lfloor \log{l} \rfloor&amp;lt;/tex&amp;gt;. Тогда наши строки совпадают, если &amp;lt;tex&amp;gt;c[k][i] = c[k][j]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;c[k][i + l - 2^k] = c[k][j + l - 2^k]&amp;lt;/tex&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Итоговая асимптотика алгоритма: предподсчет за построение суффиксного массива и &amp;lt;tex&amp;gt;O(\log(|s|))&amp;lt;/tex&amp;gt; на запрос, если предподсчитать все &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Основные определения. Простые комбинаторные свойства слов]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53362</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53362"/>
				<updated>2016-04-16T18:56:00Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Источники информации */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#palindrome | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Основные определения. Простые комбинаторные свойства слов]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53361</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53361"/>
				<updated>2016-04-16T18:53:44Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#palindrome | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53360</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53360"/>
				<updated>2016-04-16T18:44:36Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Идея */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = \min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53359</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53359"/>
				<updated>2016-04-16T18:44:03Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* См. также */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z-функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53358</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53358"/>
				<updated>2016-04-16T18:42:40Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Уточнение постановки */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — количество палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; — аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z — функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53357</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53357"/>
				<updated>2016-04-16T18:41:26Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Идея */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; - количеств палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; - аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Это можно лучше понять, посмотрев на рисунок. Снизу фигурными скобками обозначены равные подстроки. Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z — функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53356</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53356"/>
				<updated>2016-04-16T18:38:45Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Идея */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; - количеств палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; - аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] = k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции. Т.е. если имеем некоторый палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; с центром в позиции &amp;lt;tex&amp;gt;l \leqslant i \leqslant r&amp;lt;/tex&amp;gt;, то в позиции &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, симметричной &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; относительно отрезка &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt; тоже может находиться палиндром длины &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.  Однако стоит не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z — функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53355</id>
		<title>Алгоритм Манакера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D0%BD%D0%B0%D0%BA%D0%B5%D1%80%D0%B0&amp;diff=53355"/>
				<updated>2016-04-16T18:29:38Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.37: /* Идея */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Шаблон:Задача&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть дана строка &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Требуется найти количество подстрок &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, являющиеся палиндромами. Более формально, все такие пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, что &amp;lt;tex&amp;gt;s[i..j]&amp;lt;/tex&amp;gt; — [[Основные_определения,_связанные_со_строками#Отношения_между_строками | палиндром]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Уточнение постановки==&lt;br /&gt;
Легко увидеть, что таких подстрок в худшем случае будет &amp;lt;tex&amp;gt;n^2&amp;lt;/tex&amp;gt;. Значит, нужно найти компактный способ хранения информации о них. Пусть &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; - количеств палиндромов нечетной длины с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;d2[i]&amp;lt;/tex&amp;gt; - аналогичная величина для палиндромов четной длины. Далее научимся вычислять значения этих массивов.&lt;br /&gt;
&lt;br /&gt;
== Наивный алгоритм ==&lt;br /&gt;
===Идея===&lt;br /&gt;
Опишем сначала наивный алгоритм решения задачи. Чтобы посчитать ответ для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, будем на каждом шаге увеличивать длину палиндрома с центром в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и убеждаться, что рассматриваемая строка не перестала быть палиндромом, либо не произошел выход за границы массива. Очевидно, что такой алгоритм будет работать за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;d1, d2&amp;lt;/tex&amp;gt; {{---}} массивы для записи ответа&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''(int[], int[])''' calculate('''string''' s):&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     d1[i] = 1&lt;br /&gt;
     '''while''' i - d1[i] &amp;gt; 0 '''and''' i + d1[i] &amp;lt;= n '''and''' s[i - d1[i]] == s[i + d1[i]]&lt;br /&gt;
       d1[i]++&lt;br /&gt;
     d2[i] = 0&lt;br /&gt;
     '''while''' i - d2[i] - 1 &amp;gt; 0 '''and''' i + d2[i] &amp;lt;= n '''and''' s[i - d2[i] - 1] == s[i + d2[i]]&lt;br /&gt;
       d2[i]++&lt;br /&gt;
   '''return''' (d1, d2)&lt;br /&gt;
&lt;br /&gt;
==Алгоритм Манакера==&lt;br /&gt;
===Идея===&lt;br /&gt;
Алгоритм, который будет описан далее, отличается от наивного тем, что использует значения, посчитанные ранее. &lt;br /&gt;
Будем поддерживать границы самого правого из найденных палиндромов — &amp;lt;tex&amp;gt;[l; r]&amp;lt;/tex&amp;gt;. Итак, пусть мы хотим вычислить &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; — т.е. длину наибольшего палиндрома с центром в позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. При этом все предыдущие значения в массиве &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; уже посчитаны. Возможны два случая:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. текущая позиция не попадает в границы самого правого из найденных палиндромов. Тогда просто запустим наивный алгоритм для позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Тогда попробуем воспользоваться значениями, посчитанным ранее. Отразим нашу текущую позицию внутри палиндрома &amp;lt;tex&amp;gt;[l;r] : j = (r - i) + l&amp;lt;/tex&amp;gt;. Поскольку &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; — симметричные позиции, то если &amp;lt;tex&amp;gt;d1[j] = k&amp;lt;/tex&amp;gt;, мы можем утверждать, что и &amp;lt;tex&amp;gt;d1[i] &amp;gt;= k&amp;lt;/tex&amp;gt;. Это объясняется тем, что палиндром симметричен относительно своей центральной позиции (т.е. его левая половина равна его правой половине, записанной в обратном порядке). Однако надо не забыть про один граничный случай: что если &amp;lt;tex&amp;gt;i + d1[j] - 1&amp;lt;/tex&amp;gt; выходит за границы самого правого палиндрома? Так как информации о том, что происходит за границами это палинлрома у нас нет (а значит мы не можем утверждать, что симметрия сохраняется), то необходимо ограничить значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt; следующим образом: &amp;lt;tex&amp;gt;d1[i] = min(r - i, d1[j])&amp;lt;/tex&amp;gt;. После этого запустим наивный алгоритм, который будет увеличивать значение &amp;lt;tex&amp;gt;d1[i]&amp;lt;/tex&amp;gt;, пока это возможно.&lt;br /&gt;
&lt;br /&gt;
После каждого шага важно не забывать обновлять значения &amp;lt;tex&amp;gt;[l;r]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt; считается аналогичным образом, нужно лишь немного изменить индексы.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Манакер.png]]&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Приведем код, который вычисляет значения массива &amp;lt;tex&amp;gt;d1&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate1('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i, d[r - i + l])&lt;br /&gt;
     '''while''' i + k + 1 &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k + 1] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d1[i] = k&lt;br /&gt;
      '''if''' i + k &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k&lt;br /&gt;
   '''return''' d1&lt;br /&gt;
&lt;br /&gt;
Вычисление значений массива &amp;lt;tex&amp;gt;d2&amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;// &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} исходная строка&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''int[]''' calculate2('''string''' s):&lt;br /&gt;
   '''int''' l = 0&lt;br /&gt;
   '''int''' r = -1&lt;br /&gt;
   '''for''' i = 1 '''to''' n&lt;br /&gt;
     '''int''' k = 0&lt;br /&gt;
     '''if''' i &amp;lt;= r&lt;br /&gt;
        k = min(r - i + 1, d[r - i + l + 1])&lt;br /&gt;
     '''while''' i + k &amp;lt;= n '''and''' i - k - 1 &amp;gt; 0 '''and''' s[i + k] == s[i - k - 1]&lt;br /&gt;
        k++&lt;br /&gt;
      d2[i] = k&lt;br /&gt;
      '''if''' i + k - 1 &amp;gt; r&lt;br /&gt;
        l = i - k&lt;br /&gt;
        r = i + k - 1&lt;br /&gt;
   '''return''' d2&lt;br /&gt;
&lt;br /&gt;
===Оценка сложности===&lt;br /&gt;
Внешний цикл в приведенном алгоритме выполняется ровно &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; — длина строки. Попытаемся понять, сколько раз будет выполнен внутренний цикл, ответственный за наивный подсчет значений. Заметим, что каждая итерация вложенного цикла приводит к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Действительно, возможны следующие случаи:&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;tex&amp;gt;i &amp;gt; r&amp;lt;/tex&amp;gt;, т.е. сразу будет запущен наивный алгоритм и каждая его итерация будет увеличивать значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;i \leqslant r&amp;lt;/tex&amp;gt;. Здесь опять два случая:&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 \leqslant r&amp;lt;/tex&amp;gt;, но тогда, очевидно, ни одной итерации вложенного цикла выполнено не будет.&lt;br /&gt;
## &amp;lt;tex&amp;gt;i + d[j] - 1 &amp;gt; r&amp;lt;/tex&amp;gt;,  тогда каждая итерация вложенного цикла приведет к увеличению &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; хотя бы на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Т.к. значение &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; не может увеличиваться более &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз, то описанный выше алгоритм работает за время &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Префикс-функция]]&lt;br /&gt;
* [[Z — функция]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*[http://e-maxx.ru/algo/palindromes_count MAXimal :: algo :: Нахождение всех подпалиндромов]&lt;br /&gt;
* [[wikipedia:ru:Поиск_длиннейшей_подстроки-палиндрома| Википедия — Поиск длиннейшей подстроки-палиндрома]]&lt;br /&gt;
*[https://habrahabr.ru/post/276195/ Алгоритмы для поиска палиндромов — Хабр]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>217.66.158.37</name></author>	</entry>

	</feed>