<?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=109.188.168.237&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=109.188.168.237&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/109.188.168.237"/>
		<updated>2026-04-23T18:41:13Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<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%9A%D0%B0%D1%80%D0%BA%D0%BA%D0%B0%D0%B9%D0%BD%D0%B5%D0%BD%D0%B0-%D0%A1%D0%B0%D0%BD%D0%B4%D0%B5%D1%80%D1%81%D0%B0&amp;diff=20112</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%9A%D0%B0%D1%80%D0%BA%D0%BA%D0%B0%D0%B9%D0%BD%D0%B5%D0%BD%D0%B0-%D0%A1%D0%B0%D0%BD%D0%B4%D0%B5%D1%80%D1%81%D0%B0&amp;diff=20112"/>
				<updated>2012-03-29T10:37:49Z</updated>
		
		<summary type="html">&lt;p&gt;109.188.168.237: /* Шаг 2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Алгоритм Каркайнена-Сандерса (Karkkainen, Sanders) — алгоритм построения [[суффиксный массив | суффиксного массива]] за линейное время.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=&lt;br /&gt;
'''Четным суффиксом''' назовем суффикс, начинающийся в четной позиции. &amp;lt;br&amp;gt;&lt;br /&gt;
'''Нечетным суффиксом''' — суффикс, начинающийся в нечетной позиции.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Базовая идея ==&lt;br /&gt;
Алгоритм базируется на алгоритме Фараха&amp;lt;ref&amp;gt;M. Farach. Optimal suffix tree construction with large alphabets. http://www.cs.rutgers.edu/~farach/pubs/FarFerrMuthu00.pdf &amp;lt;/ref&amp;gt; построения суффиксного дерева за линейное время:&lt;br /&gt;
# Строим суффиксное дерево для четных суффиксов рекурсивно сведя задачу к построению суффиксного дерева для строки половинной длины.&lt;br /&gt;
# Строим суффиксное дерево для нечетных суффиксов за линейное время, используя результат для четных позиций.&lt;br /&gt;
# Сливаем суффиксные деревья за линейное время.&lt;br /&gt;
&lt;br /&gt;
Получили асимптотическое уравнение &amp;lt;tex&amp;gt; T(n) = T(\frac{n}{2}) + O(n) &amp;lt;/tex&amp;gt;, решением которого является &amp;lt;tex&amp;gt; T(n) = O(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм == &lt;br /&gt;
Для упрощения алгоритма вначале дополним нашу строку до четной длины (например, добавлением $ в конец). На шаге сливания мы сможем избавиться от него.&lt;br /&gt;
=== Шаг 1 ===&lt;br /&gt;
На первом шаге мы строим суффиксный массив &amp;lt;tex&amp;gt; A_{S_e} &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;tex&amp;gt; n &amp;lt;/tex&amp;gt; в строку &amp;lt;tex&amp;gt; S' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; \frac{n}{2} &amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
#* Сделаем список, состоящий из пар символов вида &amp;lt;tex&amp;gt; S[2i]S[2i + 1] &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; i \in [0; n / 2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
#* Отсортируем его цифровой сортировкой за линейное время и получим новый алфавит &amp;lt;tex&amp;gt; \Sigma' &amp;lt;/tex&amp;gt;.&lt;br /&gt;
#* Перекодируем строку &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; в алфавит &amp;lt;tex&amp;gt; \Sigma' &amp;lt;/tex&amp;gt;, получив строку &amp;lt;tex&amp;gt; S' &amp;lt;/tex&amp;gt; половинной длины.&lt;br /&gt;
# Рекурсивно построим суффиксный массив &amp;lt;tex&amp;gt; A_{S'} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Построим суффиксный массив &amp;lt;tex&amp;gt; A_{S_e} &amp;lt;/tex&amp;gt;. Очевидно, &amp;lt;tex&amp;gt; A_{S_e}[i] = 2 A_{S'}[i] &amp;lt;/tex&amp;gt;, так отношение упорядоченности любых двух строк в старом алфавите &amp;lt;tex&amp;gt; \Sigma &amp;lt;/tex&amp;gt; эквивалентно отношению упорядоченности в новом алфавите &amp;lt;tex&amp;gt; \Sigma' &amp;lt;/tex&amp;gt; по его построению.&lt;br /&gt;
&lt;br /&gt;
=== Шаг 2 ===&lt;br /&gt;
На этом шаге мы за линейное время получим суффиксный массив &amp;lt;tex&amp;gt; A_{S_o} &amp;lt;/tex&amp;gt; для нечетных суффиксов, используя уже построенный &amp;lt;tex&amp;gt; A_{S_e} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Заметим, что сортировка множества нечетных суффиксов &amp;lt;tex&amp;gt; \{ S[i..n] | i \mod 2 == 1 \} &amp;lt;/tex&amp;gt; аналогична сортировке множества пар &amp;lt;tex&amp;gt; \{ (S[i], S[i+1..n]) | i \mod 2 == 1 \} &amp;lt;/tex&amp;gt;. Однако &amp;lt;tex&amp;gt; S[i+1..n] &amp;lt;/tex&amp;gt; — четный суффикс, и его относительную позицию мы уже узнали на шаге 1.&lt;br /&gt;
&lt;br /&gt;
Таким образом, чтобы отсортировать эти пары за линейное время, сначала сразу выпишем их в порядке возрастания второго элемента пары (то есть в порядке вхождения в массив &amp;lt;tex&amp;gt; A_{S_e} &amp;lt;/tex&amp;gt;), а потом отсортируем устойчивой сортировкой подсчетом по первым элементам. Так была потребована четность длины строки, последним суффиксом будет нечетный, ему будет соответствовать пара &amp;lt;tex&amp;gt; (S[n-1], n) &amp;lt;/tex&amp;gt;. Псевдокод этого шага:&lt;br /&gt;
 M = []&lt;br /&gt;
 M.add(Pair(S[n-1], n))&lt;br /&gt;
 for i = 0..n/2 - 1:&lt;br /&gt;
     if &amp;lt;tex&amp;gt; A_{S_e}[i] &amp;lt;/tex&amp;gt; == 0: //перед первым положительным суффиксом ничего не может стоять, поэтому пропускаем его&lt;br /&gt;
         continue &lt;br /&gt;
     else:&lt;br /&gt;
         M.add(Pair(S[&amp;lt;tex&amp;gt; A_{S_e}[i] &amp;lt;/tex&amp;gt;-1], &amp;lt;tex&amp;gt; A_{S_e}[i]&amp;lt;/tex&amp;gt;))&lt;br /&gt;
&lt;br /&gt;
Заметим, что массив &amp;lt;tex&amp;gt; M &amp;lt;/tex&amp;gt; явно не отсортирован по вторым элементам и хранит не суффиксы, а их позиции в строке &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt;, но главное — что он отсортирован по возрастанию соответствующих этим позициям четным суффиксам. После устойчивой сортировки массива &amp;lt;tex&amp;gt; M &amp;lt;/tex&amp;gt; подсчетом по первому элементу легко восстановить массив &amp;lt;tex&amp;gt; A_{S_o} &amp;lt;/tex&amp;gt;:&lt;br /&gt;
 &amp;lt;tex&amp;gt; A_{S_o} &amp;lt;/tex&amp;gt; = []&lt;br /&gt;
 for i = 0..n/2 - 1:&lt;br /&gt;
    &amp;lt;tex&amp;gt; A_{S_o} &amp;lt;/tex&amp;gt;.add(M[i].second - 1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Получили, что весь второй шаг требует &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
=== Шаг 3 ===&lt;br /&gt;
Для суффиксного дерева третий шаг алгоритма опирается на специфические особенности суффиксных деревьев, которые не присущи суффиксным массивам.  &lt;br /&gt;
В случае суффиксного массива слияние становится очень сложным &amp;lt;ref&amp;gt; D. K. Kim, J. S. Sim, H. Park, and K. Park. Linear-time construction of suffix arrays. http://www.springerlink.com/content/568156021q45r320/&amp;lt;/ref&amp;gt;. Однако простой модификацией алгоритма можно значительно упростить его.&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
Покажем первые два шага агоритма для строки '''abaaab'''.&lt;br /&gt;
&lt;br /&gt;
Во-первых, добавим защитный символ $, получив строку '''abaaab$'''. Во-вторых, дополним ее до четной длины, получив '''abaaab$$'''.&lt;br /&gt;
&lt;br /&gt;
==== Шаг 1 ====&lt;br /&gt;
# В новом алфавите &amp;lt;tex&amp;gt; \Sigma' &amp;lt;/tex&amp;gt; будет три элемента — '''ab''', '''aa''', '''$$'''. Они получат номера 2, 1 и 0 соответственно.&lt;br /&gt;
# Сжатой строкой &amp;lt;tex&amp;gt; S' &amp;lt;/tex&amp;gt; будет '''2120'''.&lt;br /&gt;
# После рекурсивного вызова получим, что &amp;lt;tex&amp;gt; A_{S'} &amp;lt;/tex&amp;gt; = [3, 1, 2, 0], и &amp;lt;tex&amp;gt; A_{S_e} &amp;lt;/tex&amp;gt; = [6, 2, 4, 0].&lt;br /&gt;
&lt;br /&gt;
==== Шаг 2 ====&lt;br /&gt;
# Обойдя массив &amp;lt;tex&amp;gt; A_{S_e} &amp;lt;/tex&amp;gt;, получим M = [('''b''', 6), ('''b''', 2), ('''a''', 4), ('''$''', 8)].&lt;br /&gt;
# После сортировки подсчетом по первому элементу, получим M = [('''$''', 8), ('''a''', 4), ('''b''', 6), ('''b''', 2)].&lt;br /&gt;
# Восстановив массив &amp;lt;tex&amp;gt; A_{S_o} &amp;lt;/tex&amp;gt;, получаем [7, 3, 5, 1], что действительно является суффиксным массивом для нечетных суффиксов.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм skew == &lt;br /&gt;
Изменим изначальный алгоритм следующим образом:&lt;br /&gt;
# Построим суффиксный массив для суффиксов, соответствующих не кратным трем позициям. Рекурсивно сведем это к построению суффиксного массива для строки длиной в две трети исходной.&lt;br /&gt;
# Построим суффиксный массив для суффиксов, соответствующих кратных трем позициям, используя результат первого шага за линейное время.&lt;br /&gt;
# Сливаем эти суффиксные массивы в один за линейное время.&lt;br /&gt;
&lt;br /&gt;
Получили асимптотическое уравнение &amp;lt;tex&amp;gt; T(n) = T(\frac23 n) + O(n) &amp;lt;/tex&amp;gt;, решением которого также является &amp;lt;tex&amp;gt; T(n) = O(n) &amp;lt;/tex&amp;gt; (это видно из того, что сумма геометрической прогрессии с основанием &amp;lt;tex&amp;gt; \frac23 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; 3n &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
{{TODO| t = впилить описание сливания }}&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>109.188.168.237</name></author>	</entry>

	</feed>