Декомпозиция Линдона — различия между версиями
Shersh (обсуждение | вклад) (→Существование и единственность: утверждение в лемме) |
Shersh (обсуждение | вклад) (→Существование и единственность: рефакторинг доказательства) |
||
Строка 24: | Строка 24: | ||
|statement=<tex>s </tex>, <tex>t</tex> {{---}} простые и <tex>s < t</tex> лексикографически. Тогда верны следующие утверждения: | |statement=<tex>s </tex>, <tex>t</tex> {{---}} простые и <tex>s < t</tex> лексикографически. Тогда верны следующие утверждения: | ||
− | 1. <tex>s + t < t</tex> | + | <tex> 1. </tex> <tex>s + t < t</tex> |
− | 2. <tex>s + t</tex> {{---}} простая | + | <tex> 2. </tex> <tex>s + t</tex> {{---}} простая |
|proof= | |proof= | ||
− | 1. Так как <tex>s < t</tex>, то <tex>\exists i : s[i] < t[i]</tex> и <tex>s[j] = t[j]</tex>, <tex>j < i \Rightarrow s + t < t</tex> | + | <tex>1. </tex> Так как <tex>s < t</tex>, то <tex>\exists i : s[i] < t[i]</tex> и <tex>s[j] = t[j]</tex>, <tex>j < i \Rightarrow s + t < t</tex> |
− | 2. Пусть <tex>u</tex> {{---}} суффикс строки <tex>s + t</tex>. Тогда рассмотрим <tex> 3 </tex> возможных случая: | + | <tex>2.</tex> Пусть <tex>u</tex> {{---}} суффикс строки <tex>s + t</tex>. Тогда рассмотрим <tex> 3 </tex> возможных случая: |
− | * <tex>|u| = |t| \Rightarrow u = t \Rightarrow u > s + t</tex> по пункту <tex> 1 </tex> | + | * <tex>|u| = |t| \Rightarrow u = t \Rightarrow u > s + t</tex> по пункту <tex> 1 </tex> |
* <tex>|u| < |t| \Rightarrow u</tex> {{---}} суффикс <tex>t</tex>. Так как <tex>t</tex> {{---}} простая, и <tex>t < u </tex> по определению <tex> \Rightarrow s + t < t < u</tex> | * <tex>|u| < |t| \Rightarrow u</tex> {{---}} суффикс <tex>t</tex>. Так как <tex>t</tex> {{---}} простая, и <tex>t < u </tex> по определению <tex> \Rightarrow s + t < t < u</tex> | ||
* <tex>|u| > |t| \Rightarrow s = s' + s''</tex>, <tex>u = s'' + t</tex>. Так как <tex>s</tex> {{---}} простая, то её суффикс <tex> s'' </tex> меньше самой строки <tex> s </tex> в каком символе, значит, <tex> s + t < s'' + t</tex> | * <tex>|u| > |t| \Rightarrow s = s' + s''</tex>, <tex>u = s'' + t</tex>. Так как <tex>s</tex> {{---}} простая, то её суффикс <tex> s'' </tex> меньше самой строки <tex> s </tex> в каком символе, значит, <tex> s + t < s'' + t</tex> | ||
Строка 42: | Строка 42: | ||
|statement=Можно построить декомпозицию Линдона любой строки <tex>s</tex>, причем единственным образом. | |statement=Можно построить декомпозицию Линдона любой строки <tex>s</tex>, причем единственным образом. | ||
|proof= | |proof= | ||
− | 1. Существование. | + | '''1. Существование.''' |
У каждой строки существует хотя бы одно разбиение на простые слова. Это следует из того, что отдельный символ является простым словом. Тогда среди всех разбиений строки на простые слова возьмём то, в котором меньше всего слов. Покажем, что это и будет декомпозицией Линдона данной строки. | У каждой строки существует хотя бы одно разбиение на простые слова. Это следует из того, что отдельный символ является простым словом. Тогда среди всех разбиений строки на простые слова возьмём то, в котором меньше всего слов. Покажем, что это и будет декомпозицией Линдона данной строки. | ||
Строка 50: | Строка 50: | ||
Таким образом доказали даже более сильное утверждение: <tex>s = s_1 s_2 ... s_k</tex>, <tex> k </tex> {{---}} минимально <tex>\Leftrightarrow</tex> нет <tex>s_i < s_{i+1}</tex> | Таким образом доказали даже более сильное утверждение: <tex>s = s_1 s_2 ... s_k</tex>, <tex> k </tex> {{---}} минимально <tex>\Leftrightarrow</tex> нет <tex>s_i < s_{i+1}</tex> | ||
− | 2. Единственность. | + | '''2. Единственность.''' |
Пусть существует несколько разбиений <tex>s = s_1s_2...s_k = s_1's_2'...s_k'</tex>, | Пусть существует несколько разбиений <tex>s = s_1s_2...s_k = s_1's_2'...s_k'</tex>, | ||
Строка 60: | Строка 60: | ||
Покажем, что такого не может быть: | Покажем, что такого не может быть: | ||
− | 1) Пусть <tex>|s_i| > |s_i'|</tex>, тогда <tex>s_i = s_i's_{i+1}'...t</tex>, где <tex>t</tex> {{---}} префикс <tex>s_{j+1}'</tex>, <tex>i < j</tex>. | + | <tex> 1) </tex> Пусть <tex>|s_i| > |s_i'|</tex>, тогда <tex>s_i = s_i's_{i+1}'...t</tex>, где <tex>t</tex> {{---}} префикс <tex>s_{j+1}'</tex>, <tex>i < j</tex>. Тогда получаем: |
+ | * <tex>s_i < t</tex> (<tex>s_i</tex> {{---}} простая cтрока и по определению меньше своего суффикса) | ||
+ | * <tex>t < s_{j+1}'</tex> (<tex>t</tex> {{---}} префикс <tex>s_{j+1}'</tex>) | ||
+ | * <tex>s_{j+1}' \leqslant s_i'</tex> (по условию разбиения) | ||
+ | * <tex>s_i' < s_i</tex> (их начало совпадает, и <tex>|s_i| < |s_i'|</tex> по предположению) | ||
+ | Пришли к противоречию: <tex>s_i < s_i</tex>. | ||
− | + | <tex> 2) </tex> Случай <tex>|s_i| < |s_i'|</tex> симметричен разобранному. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
То есть не может быть строк <tex>s_i</tex> несовпадающей длины, значит, разбиения равны. | То есть не может быть строк <tex>s_i</tex> несовпадающей длины, значит, разбиения равны. |
Версия 20:21, 4 мая 2014
Декомпозиция Линдона была изобретена Роджером Линдоном (англ. Roger Lyndon) в 1954 году. Она используется для нахождения лексикографически минимального и максимального суффиксов строки, а также лексикографически минимального циклического сдвига.
Содержание
Основные определения
Определение: |
Простая строка — строка, которая лексикографически меньше любого своего суффикса. |
Примеры:
— простая строка, так как , , , .
— не простая строка, так как .
Определение: |
Декомпозиция Линдона (англ. Lyndon decomposition) строки | — её разложение , где строки просты, и при этом .
Существование и единственность
Лемма: |
— простая |
Доказательство: |
Так как , то и , Пусть — суффикс строки . Тогда рассмотрим возможных случая:
|
Теорема (Чен-Линдон-Фокс): |
Можно построить декомпозицию Линдона любой строки , причем единственным образом. |
Доказательство: |
1. Существование. У каждой строки существует хотя бы одно разбиение на простые слова. Это следует из того, что отдельный символ является простым словом. Тогда среди всех разбиений строки на простые слова возьмём то, в котором меньше всего слов. Покажем, что это и будет декомпозицией Линдона данной строки. Предположим, что это не так. Значит, леммы следует, что эти слова можно сконкатенировать и получить разбиение строки на меньшее число слов. Получили противоречие. . Так как слова и простые, то из доказаннойТаким образом доказали даже более сильное утверждение: , — минимально нет2. Единственность. Пусть существует несколько разбиений , удовлетворяющих условию теоремы. Сравним длины первых двух слов и , если , сравним вторые и так далее. Если у всех слов длины одинаковы, то разбиения совпадают — противоречие. Иначе .Покажем, что такого не может быть: Пусть , тогда , где — префикс , . Тогда получаем:
Пришли к противоречию: .То есть не может быть строк Случай симметричен разобранному. несовпадающей длины, значит, разбиения равны. |
Алгоритм Дюваля
Алгоритм
Алгоритм Дюваля (англ. Duval's algorithm) находит для данной строки длины
декомпозицию Линдона за время с использованием дополнительной памяти. Он строит декомпозицию только на упорядоченных алфавитах. Алгоритм Дюваля относится к классу жадных алгоритмов.
Определение: |
Предпростая строка — строка | , такая что , где — некоторая простая строка, а — некоторый префикс строки .
Во время работы алгоритма строка разделена на три строки , где в строке декомпозиция Линдона уже найдена, и уже больше не используется алгоритмом; строка — это предпростая строка (причём длину простых строк внутри неё мы также запоминаем); строка — это ещё не обработанная часть строки . Алгоритм Дюваля берёт первый символ строки и пытается дописать его к строке . При этом, возможно, для какого-то префикса строки декомпозиция Линдона становится известной, и эта часть переходит к строке .
Будем поддерживаться указатель
на начало строки . Внешний цикл алгоритма будет выполняться, пока , то есть пока вся строка не перейдёт в строку . Внутри этого цикла создаются два указателя: указатель на начало строки и указатель на текущий символ в строке , с которым будет производиться сравнение. Затем будем в цикле пытаться добавить символ к строке , для чего необходимо произвести сравнение с символом . При этом будем поддерживать инвариант: — длина подстроки w.Возникают три различных случая:
1. Если
, то мы можем дописать символ к строке , не нарушив её "предпростоты". Следовательно, в этом случае мы просто увеличиваем указатели и на единицу, сохраняя инвариант.2. Если
, то, очевидно, строка станет простой. Тогда мы увеличиваем на единицу, а передвигаем обратно на , чтобы следующий символ сравнивался с первым символом . То есть получаем новую простую строку длины .3. Если
, то строка уже не может быть предпростой. Поэтому мы разбиваем предпростую строку на простые строки плюс "остаток" (префикс простой строки, возможно, пустой); простые строки добавляем в ответ (т.е. выводим их позиции, попутно передвигая указатель ), а "остаток" вместе с символом переводим обратно в строку , и останавливаем выполнение внутреннего цикла. Тем самым мы на следующей итерации внешнего цикла заново обработаем остаток, зная, что он не мог образовать предпростую строку с предыдущими простыми строками. Осталось только заметить, что при выводе позиций простых строк нам нужно знать их длину; но она равна .Реализация
string s // входная строка string[] words // декомпозиция n|s| i 0 cur 0 while i n: j i + 1 k i while j n and s[k] s[j]: if s[k] s[j]: k i else: k k + 1 j j + 1 while i k: words[cur] s[i..j - k] cur w + 1 i i + j - k;
Корректность
Покажем, что алгоритм получает нужное разложение. То есть все
- простые и лексикографически.При обработке текущего символа в первом случае просто сдвигаем указатели, не записывая ответ. Во втором случае объединяем все найденные
с и получем новую строку .Покажем, что
является простой. Рассмотрим ее суффикс. Если он начинается в середине , сравним его посимвольно со строкой , и тогда в каком-то символе он окажется больше , так как суффикс начинается с , а строка — простая и по определению меньше всех своих суффиксов. Если суффикс начинается в , то при сравнении расхождение будет в символах и . Но , так что суффикс меньше . Если же суффикс начинается в начале , отбросим общий префикс вида и придем к предыдущему случаю.В третьем случае просто выведем все
и продолжим обработку со строки , так как при добавлении перестанет удовлетворять требованиям, ведь в этом случае суффикс будет меньше .Теперь покажем, что
.Последоваельность из
будет удовлетворять условию, так как эти строки равны. Следующее слово будет иметь общий префикс с , а после него будет стоять символ, меньший следующего символа из (новое получается по третьему случаю).Асимптотика
Дополнительная память требуется только на три указателя:
.Внешний цикл
делает не более итераций, поскольку в конце каждой его итерации к результату добавляется как минимум один символ (а всего символов ).Оценим теперь количество итераций первого вложенного цикла
. Для этого рассмотрим второй вложенный цикл — он при каждом своём запуске выводит некоторое количество копий одной и той же простой строки некоторой длины . Заметим, что строка является предпростой, причём её простые строки имеют длину как раз , т.е. её длина не превосходит . Поскольку длина строки равна , а указатель увеличивается по единице на каждой итерации первого вложенного цикла , то этот цикл выполнит не более итераций. Худшим случаем является случай , и мы получаем, что первый вложенный цикл всякий раз выполняет не более итераций. Вспоминая, что всего выводится символов, получаем, что для вывода символов требуется не более итераций первого вложенного . Следовательно, алгоритм Дюваля выполняется за .Легко оценить и число сравнений символов, выполняемых алгоритмом Дюваля. Поскольку каждая итерация первого вложенного цикла
производит два сравнения символов, а также одно сравнение производится после последней итерации цикла, то общее число сравнений символов не превосходит .