<?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=176.241.103.106&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=176.241.103.106&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/176.241.103.106"/>
		<updated>2026-04-08T11:08:38Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D1%84%D1%84%D0%B8%D0%BA%D1%81%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82&amp;diff=66192</id>
		<title>Суффиксный автомат</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%83%D1%84%D1%84%D0%B8%D0%BA%D1%81%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82&amp;diff=66192"/>
				<updated>2018-08-29T22:38:21Z</updated>
		
		<summary type="html">&lt;p&gt;176.241.103.106: /* Алгоритм */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Суффиксный автомат''' (англ. ''suffix automaton'', ''directed acyclic word graph'') {{---}} минимальный [[Детерминированные_конечные_автоматы|ДКА]], который принимает все суффиксы строки и только их.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
==Описание==&lt;br /&gt;
Рассмотрим конечный алфавит &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;A^*&amp;lt;/tex&amp;gt; {{---}} набор слов в алфавите &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;. Суффиксный автомат &amp;lt;tex&amp;gt;\mathcal{A}&amp;lt;/tex&amp;gt; {{---}} это набор &amp;lt;tex&amp;gt;\langle Q, A, i, T, \delta \rangle&amp;lt;/tex&amp;gt;, где&lt;br /&gt;
* &amp;lt;tex&amp;gt;Q&amp;lt;/tex&amp;gt; {{---}} конечный набор состояний,&lt;br /&gt;
* &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; {{---}} начальное состояние,&lt;br /&gt;
* &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; {{---}} набор терминальных состояний,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\delta&amp;lt;/tex&amp;gt; {{---}} функция перехода. &lt;br /&gt;
Для &amp;lt;tex&amp;gt;q \in Q&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;a \in A&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\delta(q, a)&amp;lt;/tex&amp;gt; определена, если состояние достижимо из &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; переходом по символу &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Функция перехода распространяется на слова и &amp;lt;tex&amp;gt;\delta(q, x)&amp;lt;/tex&amp;gt; обозначает, что если она существует, то состояние достигнуто после чтения слова &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; из состояния &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Автомат &amp;lt;tex&amp;gt;\mathcal{A}&amp;lt;/tex&amp;gt; распознает язык &amp;lt;tex&amp;gt;\{x \in A^* : \delta(i, x) \in T \}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Суффиксный автомат &amp;lt;tex&amp;gt;\mathcal{A}&amp;lt;/tex&amp;gt; для строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; представляет собой [[Основные_определения_теории_графов|ациклический ориентированный граф]], с начальной вершиной и множеством терминальных вершин, рёбра которого помечены символами &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;:&lt;br /&gt;
* вершины этого графа {{---}} состояния автомата, а рёбра {{---}} переходы,&lt;br /&gt;
* каждый переход в автомате {{---}} ребро в графе, помеченное некоторым символом и все рёбра, исходящие из одной вершины имеют разные метки,&lt;br /&gt;
* одно из состояний называется начальным, из него достижимы все остальные состояния,&lt;br /&gt;
* одно или несколько состояний помечены как терминальные {{---}} если пройти от начального состояния до терминального по какому-либо пути и выписывать при этом символы на переходах, то получим один из суффиксов строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Файл:Suffix_automaton_ex.png|540px|frame|center|Пример суффиксного автомата для строки &amp;lt;tex&amp;gt;abbab&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
Состояние &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; '''принимает строку''' &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;, если существует путь из начального состояния в &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt;, такой, что если последовательно выписать буквы на рёбрах на пути, получим строку &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
Автомат '''принимает строку''' &amp;lt;tex&amp;gt;s&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;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; принимаются одним состоянием &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; произвольного автомата, то для любой строки &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; строки &amp;lt;tex&amp;gt;ax&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;bx&amp;lt;/tex&amp;gt; принимаются или не принимаются автоматом одновременно. Действительно, независимо от того, как мы пришли в состояние &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt;, если мы пройдём из него по пути, соответствующему строке &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, мы сможем точно сказать, в какое состояние мы попадём (в частности, будет ли оно финальным). Значит, любому состоянию &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; соответствует множество строк &amp;lt;tex&amp;gt;X_q&amp;lt;/tex&amp;gt;, которые переводят его в одно из конечных состояний. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
Множество &amp;lt;tex&amp;gt;X_q&amp;lt;/tex&amp;gt; называют '''правым контекстом''' состояния.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Правый контекст определен не только для состояния, но и для строк, которые оно принимает {{---}} правый контекст строк совпадает с правым контекстом состояния.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Состояний в автомате не меньше, чем различных правых контекстов у подстрок строки, для которой он построен, причём в минимальном автомате достигается нижняя оценка.&lt;br /&gt;
|proof=Допустим, что в автомате есть два состояния &amp;lt;tex&amp;gt;q_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q_2&amp;lt;/tex&amp;gt; такие что &amp;lt;tex&amp;gt;X_{q_1} = X_{q_2}&amp;lt;/tex&amp;gt;. Мы можем удалить состояние &amp;lt;tex&amp;gt;q_2&amp;lt;/tex&amp;gt; и перевести переходы, ведущие в него в состояние &amp;lt;tex&amp;gt;q_1&amp;lt;/tex&amp;gt;. Множество принимаемых строк от этого не изменится, следовательно, мы можем продолжать, пока количество состояний не будет равно числу попарно различных правых контекстов. &lt;br /&gt;
}}&lt;br /&gt;
Таким образом, ДКА является минимальным тогда и только тогда, когда правые контексты всех его состояний попарно различны.&lt;br /&gt;
В случае суффиксного автомата правый контекст &amp;lt;tex&amp;gt;X_a&amp;lt;/tex&amp;gt; строки &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; взаимнооднозначно соответствует множеству правых позиций вхождений строки &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; в строку &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Таким образом, каждое состояние автомата принимает строки с одинаковым множеством правых позиций их вхождений и обратно, все строки с таким множеством позиций принимается этим состоянием.&lt;br /&gt;
&lt;br /&gt;
==Построение==&lt;br /&gt;
===Алгоритм===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = &lt;br /&gt;
Пусть длина самой короткой строки, которая принимается состоянием &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; равно &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, тогда '''суффиксная ссылка''' &amp;lt;tex&amp;gt;\mathrm{link_q}&amp;lt;/tex&amp;gt; будет вести из этого состояния в состояние, которое принимает эту же строку без первого символа.&lt;br /&gt;
}}&lt;br /&gt;
Будем обозначать длину самой длинной строки, которая принимается состоянием &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;\mathrm{len_q}&amp;lt;/tex&amp;gt;. Длина самой короткой строки из &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; в таком случае будет равна &amp;lt;tex&amp;gt;\mathrm{len(link_q)} + 1&amp;lt;/tex&amp;gt;. &lt;br /&gt;
Суффиксный автомат может быть построен за линейное время (при константном размере алфавита) online-алгоритмом. Будем добавлять символы строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; по одному, перестраивая при этом автомат. &lt;br /&gt;
Изначально автомат состоит из одного состояния, для которого &amp;lt;tex&amp;gt;\mathrm{len(0)} = 0&amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt;\mathrm{link_0} = -1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Обозначим состояние &amp;lt;tex&amp;gt;\mathrm{last}&amp;lt;/tex&amp;gt;, соответствующее текущей строке до добавления символа &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; (изначально &amp;lt;tex&amp;gt;\mathrm{last} = 0&amp;lt;/tex&amp;gt;). &amp;lt;br&amp;gt;Создадим новое состояние &amp;lt;tex&amp;gt;\mathrm{cur}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathrm{len(cur)} = \mathrm{len(last)} + 1&amp;lt;/tex&amp;gt;. &amp;lt;br&amp;gt;Рассмотрим все переходы из &amp;lt;tex&amp;gt;\mathrm{last}&amp;lt;/tex&amp;gt; по текущему символу &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;. Если перехода нет, то добавляем переход в &amp;lt;tex&amp;gt;\mathrm{cur}&amp;lt;/tex&amp;gt;, переходим по суффиксной ссылке и повторяем процедуру снова. Если переход существует, то остановимся и обозначим текущее состояние за &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Если перехода не нашлось и по суффиксным ссылкам мы дошли до фиктивного состояния (на которое указывает &amp;lt;tex&amp;gt;\mathrm{link_0}&amp;lt;/tex&amp;gt;), то &amp;lt;tex&amp;gt;\mathrm{link_{cur}} = 0&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Допустим, что мы остановились в состоянии &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, из которого существует переход с символом &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;. Обозначим состояние, куда ведёт переход, через &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt;. Рассмотрим два случая:&amp;lt;br&amp;gt;&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;\mathrm{len(p)} + 1 = \mathrm{len(q)}&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{link(cur)} = \mathrm{q}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
# В противном случае, создадим новое состояние &amp;lt;tex&amp;gt;\mathrm{new}&amp;lt;/tex&amp;gt;, скопируем в него &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; вместе с суффиксными ссылками и переходами. &amp;lt;tex&amp;gt;\mathrm{len(new)}&amp;lt;/tex&amp;gt; присвоим значение &amp;lt;tex&amp;gt;\mathrm{len(p)} + 1&amp;lt;/tex&amp;gt;. Перенаправим суффиксную ссылку из &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;\mathrm{new}&amp;lt;/tex&amp;gt; и добавим ссылку из &amp;lt;tex&amp;gt;\mathrm{cur}&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;\mathrm{new}&amp;lt;/tex&amp;gt;. Пройдём по всем суффиксным ссылкам из состояния &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; и все переходы в состояние &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; по символу &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; перенаправим в &amp;lt;tex&amp;gt;\mathrm{new}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Обновим значение &amp;lt;tex&amp;gt;\mathrm{last} = \mathrm{cur}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Пример построения===&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Изображение !! Описание&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s1.png|x180px|center|Шаг 1.]]&lt;br /&gt;
|Изначально автомат состоит из одного начального состояния. &amp;lt;tex&amp;gt;\mathrm{last} = 0, \mathrm{len(0)} = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s2.png|x180px|center|Шаг 2.]]&lt;br /&gt;
|Добавляем символ &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;. Создаем состояние &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;. Переходов из начального состояния по символу &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; нет, перейти по суффиксным ссылкам некуда, значит добавим суффиксную ссылку &amp;lt;tex&amp;gt;\mathrm{link_{1}} = 0&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;\mathrm{last} = 1, \mathrm{len(1)} = 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s3.png|x180px|center|Шаг 3.]]&lt;br /&gt;
|Добавляем символ &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;. Создаем состояние &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;. Добавим переход из &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, откатимся по суффиксной ссылке и добавим переход из &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;. Добавим суффиксную ссылку &amp;lt;tex&amp;gt;\mathrm{link_{2}} = 0&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;\mathrm{last} = 2, \mathrm{len(2)} = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s4.png|x180px|center|Шаг 4.]]&lt;br /&gt;
|Аналогично добавим символ &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; и обновим автомат. &amp;lt;tex&amp;gt;\mathrm{last} = 3, \mathrm{len(3)} = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s5.png|x180px|center|Шаг 5.]]&lt;br /&gt;
|Добавляем символ &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;. Добавим переход из &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; и перейдем по суффиксной ссылке в начальное состояние. Из состояния &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; существует переход по символу &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s6.png|x180px|center|Шаг 6.]]&lt;br /&gt;
|Рассмотрим состояние &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;, куда существует переход. Имеем &amp;lt;tex&amp;gt;\mathrm{len(0)} + 1 \neq \mathrm{len(2)}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Создаем новое состояние &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Копируем в него все суффиксные ссылки и переходы из &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и присвоим &amp;lt;tex&amp;gt;\mathrm{len(5)} = \mathrm{len(0)} + 1 = 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Перенаправим суффиксную ссылку из &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; и добавим ссылку из &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;. Перенаправим переход &amp;lt;tex&amp;gt;0 \rightarrow 2&amp;lt;/tex&amp;gt; в состояние &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF&amp;quot; |[[Файл:Suffix_automaton_s7.png|x180px|center|Шаг 7.]]&lt;br /&gt;
|Построение автомата завершено. Чтобы пометить терминальные вершины, найдём состояние, которое принимает строку &amp;lt;tex&amp;gt;abcb&amp;lt;/tex&amp;gt; и пройдём по суффиксным ссылкам, помечая все посещенные состояния терминальными.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Реализация==&lt;br /&gt;
В приведённой ниже реализации используются следующие переменные:&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{edges[]}&amp;lt;/tex&amp;gt; {{---}} массив отображений (ключ {{---}} символ, значение {{---}} номер состояния) с переходами,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{link[]}&amp;lt;/tex&amp;gt; {{---}} массив суффиксных ссылок, &lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{len[]}&amp;lt;/tex&amp;gt; {{---}} массив длин строк,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{newState()}&amp;lt;/tex&amp;gt; {{---}} функция, которая создаёт новое состояние и возвращает его номер,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{clone()}&amp;lt;/tex&amp;gt; {{---}} функция, которая копирует состояние и возвращает номер нового состояния,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathrm{last}&amp;lt;/tex&amp;gt; {{---}} последнее состояние.&lt;br /&gt;
&lt;br /&gt;
 '''func''' addChar(c ''': char''')''':'''&lt;br /&gt;
     '''int''' cur = newState()                                       &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// создаём новое состояние и получаем его номер&amp;lt;/font&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
     '''int''' p = last&lt;br /&gt;
     '''while''' p &amp;gt;= 0 '''and''' edges[p].find(c) == ''null''&lt;br /&gt;
         edges[p][c] = cur&lt;br /&gt;
         p = link[p]&lt;br /&gt;
 &lt;br /&gt;
     '''if''' p != -1&lt;br /&gt;
         '''int''' q = edges[p][c]&lt;br /&gt;
         '''if''' len[p] + 1 == len[q]&lt;br /&gt;
             link[cur] = q&lt;br /&gt;
         '''else'''&lt;br /&gt;
             '''int''' new = clone(q)                                &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// скопируем состояние &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; и получим номер нового состояния&amp;lt;/font&amp;gt;&lt;br /&gt;
             len[new] = len[p] + 1&lt;br /&gt;
             link[q] = link[cur] = new&lt;br /&gt;
             '''while''' p &amp;gt;= 0 '''and''' edges[p][c] == q&lt;br /&gt;
                 edges[p][c] = new&lt;br /&gt;
                 p = link[p]&lt;br /&gt;
     last = cur&lt;br /&gt;
&lt;br /&gt;
==Применение==&lt;br /&gt;
===Проверка вхождения строки===&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Даны строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p&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;.&lt;br /&gt;
}}&lt;br /&gt;
Построим суффиксный автомат для строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Пусть текущее состояние {{---}} &amp;lt;tex&amp;gt;\mathrm{cur}&amp;lt;/tex&amp;gt;, изначально равно &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; (начальному состоянию).&amp;lt;br&amp;gt;&lt;br /&gt;
Будем по очереди обрабатывать символы строки &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Если из состояния &amp;lt;tex&amp;gt;\mathrm{cur}&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;p&amp;lt;/tex&amp;gt;, то она является подстрокой &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;Асимптотика {{---}} построение суфавтомата за &amp;lt;tex&amp;gt;O(|s|)&amp;lt;/tex&amp;gt;, проверка за &amp;lt;tex&amp;gt;O(|p|)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Позиция первого вхождения строки===&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Даны строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p&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;.&lt;br /&gt;
}}&lt;br /&gt;
Построим суффиксный автомат для строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
В процессе построения для каждого состояния &amp;lt;tex&amp;gt;q&amp;lt;/tex&amp;gt; будем хранить значение &amp;lt;tex&amp;gt;\mathrm{first(q)}&amp;lt;/tex&amp;gt; {{---}} позицию окончания первого вхождения строки.&lt;br /&gt;
Поддерживать позицию &amp;lt;tex&amp;gt;\mathrm{first}&amp;lt;/tex&amp;gt; можно следующим образом: при добавлении нового состояния &amp;lt;tex&amp;gt;\mathrm{first(cur)} = \mathrm{len(cur)} - 1&amp;lt;/tex&amp;gt;, а при клонировании вершины &amp;lt;tex&amp;gt;\mathrm{first(new)} = \mathrm{first(q)}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Для поиска вхождения обойдём автомат, как в предыдущей задаче. Пусть состояние &amp;lt;tex&amp;gt;p'&amp;lt;/tex&amp;gt; в автомате соответствует строке &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Тогда ответ на задачу &amp;lt;tex&amp;gt;\mathrm{first(p')} - |p| + 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&amp;lt;br&amp;gt;Асимптотика {{---}} построение суфавтомата за &amp;lt;tex&amp;gt;O(|s|)&amp;lt;/tex&amp;gt;, проверка за &amp;lt;tex&amp;gt;O(|p|)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Количество различных подстрок===&lt;br /&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;.&lt;br /&gt;
}}&lt;br /&gt;
Построим суффиксный автомат для строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Каждой подстроке в суффиксном автомате соответствует путь, тогда ответ на задачу {{---}} количество различных путей из начальной вершины. Так как суфавтомат представляет собой ациклический граф, мы можем найти [[Задача_о_числе_путей_в_ациклическом_графе|количество путей в графе методом динамического программирования]].&lt;br /&gt;
===Наибольшая общая подстрока двух строк===&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Даны строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Требуется найти наибольшую общую подстроку двух строк.&lt;br /&gt;
}}&lt;br /&gt;
Построим суффиксный автомат для строки &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Пройдём по строке &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; и для текущего символа будем искать длину наибольшей общей подстроки, которая заканчивается в текущей позиции. Для этого будем поддерживать &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; {{---}} текущее состояние и &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; {{---}} текущую длину совпадающей части.&amp;lt;br&amp;gt;&lt;br /&gt;
Изначально &amp;lt;tex&amp;gt;v = 0&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;l = 0&amp;lt;/tex&amp;gt; {{---}} совпадение пустое. Рассматриваем текущий символ &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt;. Если в автомате существует переход из текущего состояния по данному символу, то перейдем в новое состояние и увеличим длину &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;Если перехода не существует, то попробуем минимально уменьшить длину совпадающей подстроки: перейдем по суффиксной ссылке из &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; в новое состояние и примем &amp;lt;tex&amp;gt;l = \mathrm{len(v)}&amp;lt;/tex&amp;gt;. Повторим операцию до тех пор, пока не найдём переход. Если по суффиксным ссылкам мы дошли до состояния, в которое ведёт суффиксная ссылка начальной вершины, то это значит, что символа &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; нет в строке &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. В таком случае примем &amp;lt;tex&amp;gt;v = l = 0&amp;lt;/tex&amp;gt;, после чего перейдем к следующему символу строки &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Длиной наибольшей общей подстроки будет &amp;lt;tex&amp;gt;\mathrm{maxLen}&amp;lt;/tex&amp;gt; {{---}} максимум из всех значений &amp;lt;tex&amp;gt;l&amp;lt;/tex&amp;gt;, полученных в ходе работы алгоритма. Тогда ответом на задачу будет являться подстрока &amp;lt;tex&amp;gt;t[(\mathrm{maxPos} - \mathrm{maxLen} + 1) .. \mathrm{maxPos}]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;\mathrm{maxPos}&amp;lt;/tex&amp;gt; {{---}} позиция, в которой достигнут максимум.&lt;br /&gt;
&lt;br /&gt;
==Сравнение с другими суффиксными структурами==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt; {{---}} строка, для которой строим соответствующую структуру, &amp;lt;tex&amp;gt;n = |s|&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\Sigma&amp;lt;/tex&amp;gt; {{---}} [[Основные_определения:_алфавит,_слово,_язык,_конкатенация,_свободный_моноид_слов;_операции_над_языками|алфавит]].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | '''Время работы'''&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | '''Память'''&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | [[Суффиксный бор]]&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n ^ 2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n^2 + n |\Sigma|)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | [[Сжатое суффиксное дерево]]&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n \log{|\Sigma|})&amp;lt;/tex&amp;gt;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n |\Sigma|)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | [[Суффиксный массив]]&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O((n + |\Sigma|) \log{n})&amp;lt;/tex&amp;gt;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n + |\Sigma|)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | Суффиксный автомат&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n \log{|\Sigma|})&amp;lt;/tex&amp;gt;&lt;br /&gt;
| align=&amp;quot;center&amp;quot; | &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Автомат для поиска образца в тексте]]&lt;br /&gt;
* [[Алгоритм Ахо-Корасик]]&lt;br /&gt;
* [[Поиск наибольшей общей подстроки двух строк с использованием хеширования]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Maxime Crochemore, Christophe Hancart, Thierry Lecroq {{---}} Algorithms on Strings&lt;br /&gt;
* [http://codeforces.com/blog/entry/22420 А. Кульков {{---}} Лекция по суффиксным структурам]&lt;br /&gt;
* [http://e-maxx.ru/algo/suffix_automata MAXimal :: algo :: Суффиксный автомат]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Структуры данных]]&lt;br /&gt;
[[Категория: Поиск подстроки в строке]]&lt;br /&gt;
[[Категория: Точный поиск]]&lt;br /&gt;
[[Категория: Автоматы и регулярные языки]]&lt;/div&gt;</summary>
		<author><name>176.241.103.106</name></author>	</entry>

	</feed>