<?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=91.122.0.36&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=91.122.0.36&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/91.122.0.36"/>
		<updated>2026-05-22T11:50:42Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F&amp;diff=25175</id>
		<title>Префикс-функция</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F&amp;diff=25175"/>
				<updated>2012-06-12T09:43:53Z</updated>
		
		<summary type="html">&lt;p&gt;91.122.0.36: /* Время работы */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Префикс-функция строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} функция &amp;lt;tex&amp;gt;\pi(i) = max \{ k | k &amp;lt; i,&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;s[1..k] = s[i - k + 1..i] \}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Наивный алгоритм вычисляет префикс функцию непосредственно по определению, сравнивая префиксы и суффиксы строк.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 '''Prefix_function''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[1..n] = 0&lt;br /&gt;
      '''for''' i = 1 '''to''' n&lt;br /&gt;
          '''for''' k = 1 '''to''' i - 1&lt;br /&gt;
              '''if''' s[1..k] == s[i - k + 1..i]&lt;br /&gt;
                  &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[i] = k&lt;br /&gt;
      '''return''' &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
Рассмотрим строку abcabcd, для которой значение префикс-функции равно &amp;lt;tex&amp;gt;[0,0,0,1,2,3,0]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Шаг || Строка || Значение функции&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || a || 0&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || ab || 0&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || abc || 0&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || abca || 1&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || abcab || 2&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || abcabc || 3&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || abcabcd || 0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Время работы===&lt;br /&gt;
Всего &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; итераций цикла, на каждой из который происходит сравнение строк за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;, что дает в итоге &amp;lt;tex&amp;gt;O(n^3)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Оптимизация==&lt;br /&gt;
Вносятся несколько важных замечаний:&lt;br /&gt;
*Следует заметить, что &amp;lt;tex&amp;gt;\pi(i) \le \pi(i-1) + 1&amp;lt;/tex&amp;gt;. Действительно, если &amp;lt;tex&amp;gt;\pi(i) &amp;gt; \pi(i-1) + 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\pi(i) - 1 &amp;gt; \pi(i-1)&amp;lt;/tex&amp;gt;, значит в &amp;lt;tex&amp;gt;\pi(i-1)&amp;lt;/tex&amp;gt; не максимально возможное значение, получено противоречие.&lt;br /&gt;
*Нужно избавиться от явных сравнений строк. Пусть вычислено &amp;lt;tex&amp;gt;\pi(i-1)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[\pi(i-1) + 1] = s[i]&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\pi(i) = \pi(i-1) + 1&amp;lt;/tex&amp;gt;. Если  &amp;lt;tex&amp;gt;s[\pi(i) + 1] &amp;lt;/tex&amp;gt; отличается от &amp;lt;tex&amp;gt;s[i + 1]&amp;lt;/tex&amp;gt;, то нужно найти наибольшую длину &amp;lt;tex&amp;gt; k&amp;lt;/tex&amp;gt;, для которой верно &amp;lt;tex&amp;gt;\pi(i) = k + 1&amp;lt;/tex&amp;gt;. Когда найдется такое &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; достаточно будет сравнить &amp;lt;tex&amp;gt;s[k + 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[i]&amp;lt;/tex&amp;gt;, при их равенстве &amp;lt;tex&amp;gt;\pi(i) = k + 1&amp;lt;/tex&amp;gt; будет верно. Итеративно продолжается поиск &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, пока оно больше нуля. Если &amp;lt;tex&amp;gt;k=0&amp;lt;/tex&amp;gt;, то при &amp;lt;tex&amp;gt;s[i] = s[1]&amp;lt;/tex&amp;gt; значение &amp;lt;tex&amp;gt;\pi(i)=1&amp;lt;/tex&amp;gt; , иначе нулю. Общая схема алгоритма есть, теперь нужно научиться искать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
*За исходное &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; нужно взять &amp;lt;tex&amp;gt;\pi(i - 1)&amp;lt;/tex&amp;gt;, что следует из первого пункта. Как видно из рисунка, приведенного ниже, при совпадении символов &amp;lt;tex&amp;gt;s[k + 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[i]&amp;lt;/tex&amp;gt; длина наибольшего общего префикса увеличивается на единицу. В случае, когда символы &amp;lt;tex&amp;gt;s[k+1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;s[i]&amp;lt;/tex&amp;gt; не совпадают, &amp;lt;tex&amp;gt;\pi(k)&amp;lt;/tex&amp;gt; {{---}} следующая по максимальности длина потенциального наибольшего общего префикса, что тоже понятно из рисунка. Последнее утверждение верно, пока &amp;lt;tex&amp;gt;k&amp;gt;0&amp;lt;/tex&amp;gt;, что позволит всегда найти его следующее значение.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Prefix2.jpg‎]]&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
 '''Prefix_function''' (&amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;)&lt;br /&gt;
      &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[1] = 0&lt;br /&gt;
      k = 0&lt;br /&gt;
      '''for''' i = 2 '''to''' n&lt;br /&gt;
          '''while''' k &amp;gt; 0 &amp;amp;&amp;amp; s[i] != s[k + 1]&lt;br /&gt;
              k = &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[k]&lt;br /&gt;
          '''if''' s[i] == s[k + 1]&lt;br /&gt;
              k++&lt;br /&gt;
          &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[i] = k&lt;br /&gt;
      '''return''' &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Время работы===&lt;br /&gt;
Время работы алгоритма составит &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Для доказательства этого потребуется новое обозначение &amp;lt;tex&amp;gt;w_i&amp;lt;/tex&amp;gt; {{---}} количество итераций цикла &amp;lt;tex&amp;gt;while&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом шаге. Итоговое время работы алгоритма составит &amp;lt;tex&amp;gt;\sum\limits_{i=2}^n w_i&amp;lt;/tex&amp;gt;. Теперь стоит отметить, что &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; увеличивается на каждом шаге не более чем на единицу, значит максимально возможное значение &amp;lt;tex&amp;gt;k = n - 1.&amp;lt;/tex&amp;gt; Внутри цикла &amp;lt;tex&amp;gt;while&amp;lt;/tex&amp;gt; значение &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; лишь уменьшается, а из предыдущего утверждения получается, что оно не может уменьшиться больше, чем &amp;lt;tex&amp;gt;n-1&amp;lt;/tex&amp;gt; раз, значит &amp;lt;tex&amp;gt;\sum\limits_{i=2}^n w_i \le 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;
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296.&lt;/div&gt;</summary>
		<author><name>91.122.0.36</name></author>	</entry>

	</feed>