<?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=89.110.14.141&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=89.110.14.141&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/89.110.14.141"/>
		<updated>2026-04-11T06:03:33Z</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=22244</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=22244"/>
				<updated>2012-05-13T09:52:16Z</updated>
		
		<summary type="html">&lt;p&gt;89.110.14.141: /* Оптимизация */&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;
Рассмотрим строку 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;
 '''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; = []&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;
Всего &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)&amp;lt;/tex&amp;gt; превосходит &amp;lt;tex&amp;gt;\pi(i-1)&amp;lt;/tex&amp;gt; не больше, чем на &amp;lt;tex&amp;gt;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] = 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;\pi(i) = 1&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;s[i] = s[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;k = \pi(k)&amp;lt;/tex&amp;gt;, когда &amp;lt;tex&amp;gt;s[k+1] = s[i]&amp;lt;/tex&amp;gt; ложно, взяв за исходное &amp;lt;tex&amp;gt; k = \pi(i -1)&amp;lt;/tex&amp;gt;, это позволит выбирать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; по убыванию вплоть до нуля, так как очевидно, что &amp;lt;tex&amp;gt;\pi(x) \geq \pi(\pi(x))&amp;lt;/tex&amp;gt; для любых &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&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; = 0&lt;br /&gt;
      '''for''' i = 2 '''to''' n&lt;br /&gt;
          k = &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[i - 1] &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;O(1)&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>89.110.14.141</name></author>	</entry>

	<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=22243</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=22243"/>
				<updated>2012-05-13T09:51:11Z</updated>
		
		<summary type="html">&lt;p&gt;89.110.14.141: /* Псевдокод */&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;
Рассмотрим строку 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;
 '''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; = []&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;
Всего &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)&amp;lt;/tex&amp;gt; превосходит &amp;lt;tex&amp;gt;\pi(i-1)&amp;lt;/tex&amp;gt; не больше чем на &amp;lt;tex&amp;gt;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] = 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;\pi(i) = 1&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;s[i] = s[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;k = \pi(k)&amp;lt;/tex&amp;gt;, когда &amp;lt;tex&amp;gt;s[k+1] = s[i]&amp;lt;/tex&amp;gt; ложно, взяв за исходное &amp;lt;tex&amp;gt; k = \pi(i -1)&amp;lt;/tex&amp;gt;, это позволит выбирать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; по убыванию вплоть до нуля, так как очевидно, что &amp;lt;tex&amp;gt;\pi(x) \geq \pi(\pi(x))&amp;lt;/tex&amp;gt; для любых &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&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; = 0&lt;br /&gt;
      '''for''' i = 2 '''to''' n&lt;br /&gt;
          k = &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[i - 1] &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;O(1)&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>89.110.14.141</name></author>	</entry>

	<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=22242</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=22242"/>
				<updated>2012-05-13T09:50:42Z</updated>
		
		<summary type="html">&lt;p&gt;89.110.14.141: /* Псевдокод */&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;
Рассмотрим строку 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;
 '''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; = 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;
Всего &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)&amp;lt;/tex&amp;gt; превосходит &amp;lt;tex&amp;gt;\pi(i-1)&amp;lt;/tex&amp;gt; не больше чем на &amp;lt;tex&amp;gt;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] = 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;\pi(i) = 1&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;s[i] = s[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;k = \pi(k)&amp;lt;/tex&amp;gt;, когда &amp;lt;tex&amp;gt;s[k+1] = s[i]&amp;lt;/tex&amp;gt; ложно, взяв за исходное &amp;lt;tex&amp;gt; k = \pi(i -1)&amp;lt;/tex&amp;gt;, это позволит выбирать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; по убыванию вплоть до нуля, так как очевидно, что &amp;lt;tex&amp;gt;\pi(x) \geq \pi(\pi(x))&amp;lt;/tex&amp;gt; для любых &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;.&lt;br /&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; = 0&lt;br /&gt;
      '''for''' i = 2 '''to''' n&lt;br /&gt;
          k = &amp;lt;tex&amp;gt;\pi&amp;lt;/tex&amp;gt;[i - 1] &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;O(1)&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>89.110.14.141</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=22241</id>
		<title>Поиск подстроки в строке с использованием хеширования. Алгоритм Рабина-Карпа</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8_%D0%B2_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B5_%D1%81_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC_%D1%85%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F._%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0-%D0%9A%D0%B0%D1%80%D0%BF%D0%B0&amp;diff=22241"/>
				<updated>2012-05-13T09:46:56Z</updated>
		
		<summary type="html">&lt;p&gt;89.110.14.141: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Адгоритм Рабина-Карпа предназначен для [[Наивный алгоритм поиска подстроки в строке#Постановка задачи| поиска подстроки в строке]].&lt;br /&gt;
==Метод хеширования==&lt;br /&gt;
&lt;br /&gt;
Для решения задачи удобно использовать полиномиальный хеш, так его легко пересчитывать, {{---}} &amp;lt;tex&amp;gt;hash(s[1..n]) = (p^{n - 1} s[1] + ... + p^{0} s[n])&amp;lt;/tex&amp;gt; mod &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; {{---}} это некоторое простое число, а &amp;lt;tex&amp;gt;r&amp;lt;/tex&amp;gt; {{---}} некоторое большое число, чтобы было меньше коллизий (обычно берётся &amp;lt;tex&amp;gt;2^{32}&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;2^{64}&amp;lt;/tex&amp;gt;, чтобы модуль брался автоматически при переполнении типов). Стоит обратить внимание, что если 2 строчки имеют одинаковый хэш, то они в большинстве таких случаев равны.&lt;br /&gt;
&lt;br /&gt;
При удалении первого символа строки и добавлении символа в конец считать хеш новой строки при помощи хеша изначальной строки возможно за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;hash(s[i + 1..i + m - 1]) = hash(s[i..i + m - 1]) - p^{m - 1} s[i]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;hash(s[i + 1..i + m]) = p \cdot hash(s[i + 1..i + m - 1]) + s[i + m]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Получается : &amp;lt;tex&amp;gt;hash(s[i + 1..i + m]) = p \cdot hash(s[i..i + m - 1]) - p^{m} s[i] + s[i + m]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
&lt;br /&gt;
Алгоритм начинается с подсчета &amp;lt;tex&amp;gt;hash(s[1..m])&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;hash(p[1..m])&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для &amp;lt;tex&amp;gt;i \in [1..n - m + 1]&amp;lt;/tex&amp;gt; вычисляется &amp;lt;tex&amp;gt;hash(s[i..i + m - 1]&amp;lt;/tex&amp;gt; и сравнивается с &amp;lt;tex&amp;gt;hash(p[1..m])&amp;lt;/tex&amp;gt;. Если они оказались равны {{---}} то считается, что подстрока &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; входит в строку &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; (начиная с позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;) или проверяется, что подстрока является шаблоном, для этого выбираются и сравниваются случайные символы из строк.&lt;br /&gt;
&lt;br /&gt;
Для ускорения работы алгоритма оптимально предпосчитать &amp;lt;tex&amp;gt;p^{m}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
  '''RabinKarp''' (s[1..n], p[1..m])&lt;br /&gt;
       hp = hash(p[1..m])&lt;br /&gt;
       h = hash(s[1..m])&lt;br /&gt;
       '''for''' i = 1 '''to''' n - m + 1&lt;br /&gt;
            '''if''' h = hp&lt;br /&gt;
                 answer.add(i)&lt;br /&gt;
            h = p * h - p&amp;lt;tex&amp;gt;^{m}&amp;lt;/tex&amp;gt; * hash(s[i]) + hash(s[i + m])&lt;br /&gt;
       '''if''' answer.size() == 0&lt;br /&gt;
            '''return''' not found&lt;br /&gt;
       '''else'''&lt;br /&gt;
            '''return''' answer&lt;br /&gt;
&lt;br /&gt;
Новый хеш &amp;lt;tex&amp;gt;h&amp;lt;/tex&amp;gt; был получен с помощью быстрого пересчёта. Для сохранения корректности алгоритма нужно считать, что &amp;lt;tex&amp;gt;s[n + 1]&amp;lt;/tex&amp;gt; {{---}} пустой символ.&lt;br /&gt;
&lt;br /&gt;
==Время работы==&lt;br /&gt;
&lt;br /&gt;
Изначальный подсчёт хешей выполняется за &amp;lt;tex&amp;gt;O(m)&amp;lt;/tex&amp;gt;. В цикле всего &amp;lt;tex&amp;gt;n - m + 1&amp;lt;/tex&amp;gt; итераций {{---}} каждая выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;. Итоговое время работы алгоритма &amp;lt;tex&amp;gt;O(n + m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
Кормен Т., Лейзерсон Ч., Ривест Р. Алгоритмы: построение и анализ. {{---}} 2-е изд. {{---}} М.: Издательский дом «Вильямс», 2007. {{---}} С. 1296.&lt;br /&gt;
&lt;br /&gt;
==Ссылки==&lt;br /&gt;
*[[Наивный алгоритм поиска подстроки в строке]]&lt;/div&gt;</summary>
		<author><name>89.110.14.141</name></author>	</entry>

	</feed>