Преобразование Барроуза-Уилера — различия между версиями
Evarand (обсуждение | вклад) м (Таблицы) |
Evarand (обсуждение | вклад) м (Косметические изменения) |
||
Строка 1: | Строка 1: | ||
− | |||
'''Преобразование Барроуза {{---}} Уилера''' (англ. ''Burrows-Wheeler transform'') {{---}} алгоритм, используемый для предварительной обработки данных перед сжатием, разработанный для улучшения эффективности последующего кодирования. Преобразование Барроуза {{---}} Уилера меняет порядок символов во входной строке таким образом, что повторяющиеся подстроки образуют на выходе идущие подряд последовательности одинаковых символов. | '''Преобразование Барроуза {{---}} Уилера''' (англ. ''Burrows-Wheeler transform'') {{---}} алгоритм, используемый для предварительной обработки данных перед сжатием, разработанный для улучшения эффективности последующего кодирования. Преобразование Барроуза {{---}} Уилера меняет порядок символов во входной строке таким образом, что повторяющиеся подстроки образуют на выходе идущие подряд последовательности одинаковых символов. | ||
Строка 5: | Строка 4: | ||
== Описание алгоритма == | == Описание алгоритма == | ||
− | Преобразование выполняется в три этапа | + | Преобразование выполняется в три этапа: |
− | + | # Составляется таблица всех циклических сдвигов входной строки. | |
− | + | # Производится лексикографическая (в алфавитном порядке) сортировка строк таблицы. | |
− | + | # В качестве выходной строки выбирается последний столбец таблицы преобразования и номер строки, совпадающей с исходной. | |
== Пример работы алгоритма == | == Пример работы алгоритма == | ||
Строка 17: | Строка 16: | ||
!colspan="4"|Трансформация | !colspan="4"|Трансформация | ||
|- | |- | ||
− | ! Вход || Все<br /> | + | ! Вход || Все<br />циклические <br /> сдвиги || Сортировка<br />строк || Выход |
|- | |- | ||
| | | | ||
Строка 86: | Строка 85: | ||
===Наивный алгоритм=== | ===Наивный алгоритм=== | ||
− | Пусть нам дано: <tex>$BWT(s) =$(</tex>"BCABAAA", <tex>3)</tex>. Тогда выпишем в столбик нашу преобразованную последовательность символов "BCABAAA". Запишем её как последний столбик предыдущей матрицы (при прямом преобразовании Барроуза {{---}} Уилера), при этом все предыдущие столбцы оставляем пустыми. Далее построчно отсортируем матрицу, затем в предыдущий столбец запишем "BCABAAA". Опять построчно отсортируем матрицу. Продолжая таким образом, можно восстановить полный список всех циклических перестановок строки, которую нам надо найти. Выстроив полный отсортированный список перестановок, выберем строку с номером, который нам был изначально дан. В итоге мы получим искомую строку. | + | Пусть нам дано: <tex>$BWT(s) =$(</tex>"BCABAAA", <tex>3)</tex>. Тогда выпишем в столбик нашу преобразованную последовательность символов "BCABAAA". Запишем её как последний столбик предыдущей матрицы (при прямом преобразовании Барроуза {{---}} Уилера), при этом все предыдущие столбцы оставляем пустыми. Далее построчно [[Сортировки | отсортируем]] матрицу, затем в предыдущий столбец запишем "BCABAAA". Опять построчно отсортируем матрицу. Продолжая таким образом, можно восстановить полный список всех циклических перестановок строки, которую нам надо найти. Выстроив полный отсортированный список перестановок, выберем строку с номером, который нам был изначально дан. В итоге мы получим искомую строку. |
Алгоритм обратного преобразования описан в таблице ниже: | Алгоритм обратного преобразования описан в таблице ниже: | ||
Строка 230: | Строка 229: | ||
Пусть дана строка <tex>$s$</tex>, к которой было применено преобразование BWT. Докажем, что при использовании наивного алгоритма на каждом шаге получающийся набор строк соответствует суффиксам циклических перестановок исходной строки, методом математической индукции. | Пусть дана строка <tex>$s$</tex>, к которой было применено преобразование BWT. Докажем, что при использовании наивного алгоритма на каждом шаге получающийся набор строк соответствует суффиксам циклических перестановок исходной строки, методом математической индукции. | ||
− | * База. Циклически сдвинем все строки исходной таблицы на <tex>1</tex> влево. Тогда в столбце <tex>n</tex> будут находиться символы, добавленные на первом шаге алгоритма, а в столбце <tex>n - 1</tex> символы, изначально стоявшие в таблице до первого шага алгоритма. Таким образом, полученные на первом шаге алгоритма строки являются суффиксами циклических перестановок строки <tex>$s$</tex>. | + | * '''База'''. Циклически сдвинем все строки исходной таблицы на <tex>1</tex> влево. Тогда в столбце <tex>n</tex> будут находиться символы, добавленные на первом шаге алгоритма, а в столбце <tex>n - 1</tex> символы, изначально стоявшие в таблице до первого шага алгоритма. Таким образом, полученные на первом шаге алгоритма строки являются суффиксами циклических перестановок строки <tex>$s$</tex>. |
− | * Предположение. Пусть на <tex>k</tex> шаге алгоритма все полученные строки являются суффиксами циклических перестановок строки <tex>$s$</tex>. | + | * '''Предположение'''. Пусть на <tex>k</tex> шаге алгоритма все полученные строки являются суффиксами циклических перестановок строки <tex>$s$</tex>. |
− | * Переход. Рассмотрим <tex>k+1</tex>-ый шаг алгоритма. Все строки отсортированы, поэтому самый левый столбец совпадет с <tex>1</tex> столбцом исходной таблицы. Циклически сдвинем все строки исходной таблицы на <tex>n - k</tex> символов вправо. Теперь по предположению первые <tex>k</tex> символов справа в каждой строке совпадают у исходной таблицы и у таблицы, полученной в результате работы алгоритма. <tex>k</tex>-ые справа столбцы также совпадают. Добавленный на <tex>k+1</tex>-ом шаге столбец также совпадает с <tex>k+1</tex>-ым справа столбцом сдвинутой исходной таблицы, так как совпадает с последним столбцом исходной таблицы, которая была сдвинута на <tex>n-k</tex>. | + | * '''Переход'''. Рассмотрим <tex>k+1</tex>-ый шаг алгоритма. Все строки отсортированы, поэтому самый левый столбец совпадет с <tex>1</tex> столбцом исходной таблицы. Циклически сдвинем все строки исходной таблицы на <tex>n - k</tex> символов вправо. Теперь по предположению первые <tex>k</tex> символов справа в каждой строке совпадают у исходной таблицы и у таблицы, полученной в результате работы алгоритма. <tex>k</tex>-ые справа столбцы также совпадают. Добавленный на <tex>k+1</tex>-ом шаге столбец также совпадает с <tex>k+1</tex>-ым справа столбцом сдвинутой исходной таблицы, так как совпадает с последним столбцом исходной таблицы, которая была сдвинута на <tex>n-k</tex>. |
{| class="wikitable" | {| class="wikitable" | ||
Строка 350: | Строка 349: | ||
Пусть <tex> N </tex> — количество символов во входной строке, <tex> M </tex> — количество символов в алфавите, <tex> k </tex> — номер исходной строки в матрице перестановок, <tex> s </tex> — входящая строка, <tex> count </tex> — массив для сортировки подсчетом, <tex> t </tex> — вектор обратного преобразования, <tex> x </tex> — номер данной нам строки в таблице. | Пусть <tex> N </tex> — количество символов во входной строке, <tex> M </tex> — количество символов в алфавите, <tex> k </tex> — номер исходной строки в матрице перестановок, <tex> s </tex> — входящая строка, <tex> count </tex> — массив для сортировки подсчетом, <tex> t </tex> — вектор обратного преобразования, <tex> x </tex> — номер данной нам строки в таблице. | ||
− | + | function reverseBWT(N : Int, M : Int, k : Int, s : Stirng): Int[] | |
− | + | <font color="green">// Cчитаем частоты символов</font> | |
− | + | '''for''' i = 0 .. M | |
− | + | count[i] = 0 | |
− | + | '''for''' i = 0 .. N | |
− | + | count[s[i]]++ | |
− | + | <font color="green">// Упорядочиваем символы, чтобы получить первый столбец исходной матрицы</font> | |
− | + | <font color="green">// count[i] указывает на первую позицию символа i в первом столбце</font> | |
− | + | sum = 0 | |
− | + | '''for''' i = 0 .. M | |
− | + | sum = sum + count[i] | |
− | + | count[i] = sum - count[i] | |
− | + | <font color="green">// Cоздаем вектор обратного преобразования</font> | |
− | + | '''for''' i = 0 .. N | |
− | + | t[count[s[i]]] = i | |
− | + | count[s[i]]++ | |
− | + | <font color="green">// И восстанавливаем исходный текст</font> | |
− | + | j = t[x] | |
− | + | '''for''' i = 0 .. N | |
− | + | answer[i] = s[j] | |
+ | j = t[j] | ||
+ | return answer | ||
====Доказательство корректности==== | ====Доказательство корректности==== | ||
Строка 375: | Строка 376: | ||
Пусть текст <tex>T</tex> состоит из <tex>N + 1</tex> символов, занумерованных с нуля: <tex>T[0..N]</tex>. Буквы <tex>T[i]</tex> принадлежат некоторому алфавиту <tex>A</tex>. Лексикографический порядок (строгий) на строках из алфавита <tex>A</tex> будем обозначать <tex>\preceq (\prec)</tex>. Обозначим через <tex>S_{k}T</tex> циклический сдвиг текста <tex>T</tex> на <tex>k</tex> символов влево: | Пусть текст <tex>T</tex> состоит из <tex>N + 1</tex> символов, занумерованных с нуля: <tex>T[0..N]</tex>. Буквы <tex>T[i]</tex> принадлежат некоторому алфавиту <tex>A</tex>. Лексикографический порядок (строгий) на строках из алфавита <tex>A</tex> будем обозначать <tex>\preceq (\prec)</tex>. Обозначим через <tex>S_{k}T</tex> циклический сдвиг текста <tex>T</tex> на <tex>k</tex> символов влево: | ||
:{| | :{| | ||
− | <tex> S_{k}T = T[(j + k) ( | + | <tex> S_{k}T = T[(j + k) (\bmod\ N + 1)] </tex> |
|} | |} | ||
Строка 385: | Строка 386: | ||
Преобразование Барроуза-Уилера текста <tex>T</tex> есть текст <tex>B[0..N] = BW(T)</tex>, буквы которого заданы соотношением: | Преобразование Барроуза-Уилера текста <tex>T</tex> есть текст <tex>B[0..N] = BW(T)</tex>, буквы которого заданы соотношением: | ||
:{| | :{| | ||
− | <tex>B[i] = S_{p(i)}T[N]</tex>, другими словами <tex>B[i] = S_{p(i) - 1}T[0] = T[(p(i) - 1) ( | + | <tex>B[i] = S_{p(i)}T[N]</tex>, другими словами <tex>B[i] = S_{p(i) - 1}T[0] = T[(p(i) - 1) (\bmod\ N + 1)] \ \ \textbf{(2)}</tex> |
|} | |} | ||
Строка 427: | Строка 428: | ||
===Алгоритм за линейное время=== | ===Алгоритм за линейное время=== | ||
− | Будем обозначать <tex>s^i</tex> <tex>i</tex>-ую циклическую перестановку <tex>$s$</tex>. Пусть <tex>s^0 = s_0 s_1 \ldots s_{n-1}</tex>, <tex>$BWT(s)$\;= L</tex> и <tex>L = L_0L_1\ldots L_{n-1}</tex>, <tex>I</tex> - номер строки <tex>s^0</tex> в таблице. Предподсчитаем следующие величины: | + | Будем обозначать <tex>s^i</tex> <tex>i</tex>-ую циклическую перестановку <tex>$s$</tex>. Пусть <tex>s^0 = s_0 s_1 \ldots s_{n-1}</tex>, <tex>$BWT(s)$\;= L</tex> и <tex>L = L_0L_1\ldots L_{n-1}</tex>, <tex>I</tex> -- номер строки <tex>s^0</tex> в таблице. Предподсчитаем следующие величины: |
− | * Для каждого <tex>L_i</tex> количество символов на подстроке <tex> | + | * Для каждого <tex>L_i</tex> количество символов на подстроке <tex>l_0, \ldots , l_{i-1}</tex>, равных <tex>L_i</tex> |
* Для каждого уникального <tex>L_i</tex> количество символов в <tex>L</tex>, лексикографически меньших, чем <tex>L_i</tex> | * Для каждого уникального <tex>L_i</tex> количество символов в <tex>L</tex>, лексикографически меньших, чем <tex>L_i</tex> | ||
Строка 468: | Строка 469: | ||
# <tex>L</tex>, последний столбец таблицы перестановок | # <tex>L</tex>, последний столбец таблицы перестановок | ||
# <tex>I</tex>, номер строки <tex>$s$</tex> в таблице перестановок | # <tex>I</tex>, номер строки <tex>$s$</tex> в таблице перестановок | ||
− | # Частота, с которой символ <tex>L_{i}</tex> встречается в подстроке <tex> | + | # Частота, с которой символ <tex>L_{i}</tex> встречается в подстроке <tex>l_0, \ldots , l_{i-1}</tex> |
# Для каждого уникального символа количество лексикографически меньших символов в <tex>L</tex> | # Для каждого уникального символа количество лексикографически меньших символов в <tex>L</tex> | ||
Строка 493: | Строка 494: | ||
== Дополнительно == | == Дополнительно == | ||
− | * bzip2 использует преобразование Барроуза {{---}} Уилера для превращения последовательностей многократно чередующихся символов в строки одинаковых символов, затем применяет преобразование MTF | + | * bzip2<ref>[https://ru.wikipedia.org/wiki/Bzip2 bzip2]</ref> использует преобразование Барроуза {{---}} Уилера для превращения последовательностей многократно чередующихся символов в строки одинаковых символов, затем применяет преобразование [[Преобразование_MTF | MTF]], и в конце кодирование Хаффмана. |
+ | |||
+ | == См. также == | ||
+ | * [[Алгоритм_Хаффмана | Алгоритм Хаффмана]] | ||
+ | * [[Алгоритмы_LZ77_и_LZ78 | Алгоритмы LZ77 и LZ78]] | ||
+ | * [[Арифметическое_кодирование | Арифметическое кодирование]] | ||
== Источники информации == | == Источники информации == | ||
Строка 499: | Строка 505: | ||
*[http://www.cs.karelia.ru/~aborod/inf/2010/schedule.php.ru cs.karelia.ru: Преобразование Барроуза {{---}} Уилера] | *[http://www.cs.karelia.ru/~aborod/inf/2010/schedule.php.ru cs.karelia.ru: Преобразование Барроуза {{---}} Уилера] | ||
+ | |||
+ | == Примечания == | ||
+ | <references/> | ||
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Алгоритмы сжатия ]] | [[Категория: Алгоритмы сжатия ]] |
Версия 22:15, 12 декабря 2015
Преобразование Барроуза — Уилера (англ. Burrows-Wheeler transform) — алгоритм, используемый для предварительной обработки данных перед сжатием, разработанный для улучшения эффективности последующего кодирования. Преобразование Барроуза — Уилера меняет порядок символов во входной строке таким образом, что повторяющиеся подстроки образуют на выходе идущие подряд последовательности одинаковых символов.
Содержание
Описание алгоритма
Преобразование выполняется в три этапа:
- Составляется таблица всех циклических сдвигов входной строки.
- Производится лексикографическая (в алфавитном порядке) сортировка строк таблицы.
- В качестве выходной строки выбирается последний столбец таблицы преобразования и номер строки, совпадающей с исходной.
Пример работы алгоритма
Пусть нам дана исходная строка
"ABACABA".Трансформация | |||
---|---|---|---|
Вход | Все циклические сдвиги |
Сортировка строк |
Выход |
ABACABA |
ABACABA |
AABACAB |
BCABAAA, 3 |
Результат можно записать так:
"BCABAAA", , где — номер исходной строки в отсортированной матрице. Он нужен для обратного преобразования.
Следует заметить, что иногда в исходной строке приводится так называемый символ конца строки , который в преобразовании будет считаться последним (максимальным) символом, тогда сохранение номера исходной строки не требуется.
Пусть нам дана исходная строка "ABACABA$".
Трансформация | |||
---|---|---|---|
Вход | Все Перестановки |
Сортировка Строк |
Выход |
ABACABA$ |
ABACABA$ |
ABACABA$ |
$CBBAAAA |
При аналогичном вышеприведённом преобразовании та строчка в матрице, которая будет заканчиваться на символ конца строки, и будет исходной: ("ABACABA$"). Тогда результат можно записать так:
"$CBBAAAA".Обратное преобразование
Наивный алгоритм
Пусть нам дано: отсортируем матрицу, затем в предыдущий столбец запишем "BCABAAA". Опять построчно отсортируем матрицу. Продолжая таким образом, можно восстановить полный список всех циклических перестановок строки, которую нам надо найти. Выстроив полный отсортированный список перестановок, выберем строку с номером, который нам был изначально дан. В итоге мы получим искомую строку. Алгоритм обратного преобразования описан в таблице ниже:
"BCABAAA", . Тогда выпишем в столбик нашу преобразованную последовательность символов "BCABAAA". Запишем её как последний столбик предыдущей матрицы (при прямом преобразовании Барроуза — Уилера), при этом все предыдущие столбцы оставляем пустыми. Далее построчноОбратное преобразование | |||||||
---|---|---|---|---|---|---|---|
Вход | |||||||
BCABAAA | |||||||
Добавление 1 | Сортировка 1 | Добавление 2 | Сортировка 2 | Добавление 3 | Сортировка 3 | Добавление 4 | |
B C A B A A A |
A A A A B B C |
BA CA AA BA AB AB AC |
AA AB AB AC BA BA CA |
BAA CAB AAB BAC ABA ABA ACA |
AAB ABA ABA ACA BAA BAC CAB |
BAAB CABA AABA BACA ABAA ABAC ACAB | |
Сортировка 4 | Добавление 5 | Сортировка 5 | Добавление 6 | Сортировка 6 | Добавление 7 | Сортировка 7 | |
AABA ABAA ABAC ACAB BAAB BACA CABA |
BAABA CABAA AABAC BACAB ABAAB ABACA ACABA |
AABAC ABAAB ABACA ACABA BAABA BACAB CABAA |
BAABAC CABAAB AABACA BACABA ABAABA ABACAB ACABAA |
AABACA ABAABA ABACAB ACABAA BAABAC BACABA CABAAB |
BAABACA CABAABA AABACAB BACABAA ABAABAC ABACABA ACABAAB |
AABACAB ABAABAC ABACABA ACABAAB BAABACA BACABAA CABAABA | |
Результат | |||||||
ABACABA |
Следует также заметить, что если нам было бы дано
"$CBBAAAA", то мы также получили бы нашу исходную строку, только с символом конца строки на конце: ABACABA$.Временная сложность данного алгоритма
, пространственная .Доказательство корректности
Пусть дана строка
, к которой было применено преобразование BWT. Докажем, что при использовании наивного алгоритма на каждом шаге получающийся набор строк соответствует суффиксам циклических перестановок исходной строки, методом математической индукции.- База. Циклически сдвинем все строки исходной таблицы на влево. Тогда в столбце будут находиться символы, добавленные на первом шаге алгоритма, а в столбце символы, изначально стоявшие в таблице до первого шага алгоритма. Таким образом, полученные на первом шаге алгоритма строки являются суффиксами циклических перестановок строки .
- Предположение. Пусть на шаге алгоритма все полученные строки являются суффиксами циклических перестановок строки .
- Переход. Рассмотрим -ый шаг алгоритма. Все строки отсортированы, поэтому самый левый столбец совпадет с столбцом исходной таблицы. Циклически сдвинем все строки исходной таблицы на символов вправо. Теперь по предположению первые символов справа в каждой строке совпадают у исходной таблицы и у таблицы, полученной в результате работы алгоритма. -ые справа столбцы также совпадают. Добавленный на -ом шаге столбец также совпадает с -ым справа столбцом сдвинутой исходной таблицы, так как совпадает с последним столбцом исходной таблицы, которая была сдвинута на .
шаг алгоритма при | ||
---|---|---|
Исходная таблица |
Сдвинутая таблица |
Результат работы алгоритма |
AABACAB |
CABAABA |
BAABA |
Таким образом, поскольку на каждом шаге алгоритма получившиеся строки являлись суффиксами циклических перестановок
, после последнего шага получившиеся строки будут совпадать с циклическими перестановками .Оптимизированный наивный алгоритм
Наивный алгоритм можно оптимизировать. Заметим, что при каждом проявлении неизвестного столбца выполнялись одни и те же действия. Мы приписывали новый столбец и сортировали имеющиеся данные. На каждом шагу мы к строке, которая находилась на
-ом месте приписываем в начало -ый элемент столбца входных данных. Пусть изначально мы знаем каким по порядку является приписанный нами в начало символ (то есть каким по порядку в столбце). И конечно же мы знаем исходя из предыдущего шага какое место занимала наша строка без этого первого символа ( -ое). Тогда несложно заметить, что при выполнении такой операции строка с номером всегда будет перемещаться на позицию с номером .0 | а | р | 9 | |
1 | а | д | 7 | |
2 | а | a | 0 | |
3 | а | к | 8 | |
4 | а | р | 10 | |
5 | б | a | 1 | |
6 | б | a | 2 | |
7 | д | a | 3 | |
8 | к | a | 4 | |
9 | р | б | 5 | |
10 | р | б | 6 |
Здесь слева отсортированный данный столбец, чтобы мы знали, какое место в лексикографическом порядке занимает приписываемый нами символ среди всех элементов данного нам изначально столбца. Справа - изначально данный столбец и соответствующее ему число. Поскольку в нашем алгоритме новый столбец приписывается в начало, то мы из состояния
(левый столбец) переходим в состояние (правый). Для того, чтобы восстановить строку, нам необходимо от последней такой цифры по пути из в восстановить строку.
Сложность оптимизированного алгоритмаДанный алгоритм работает за времени и требует памяти. Однако, если размер алфавита не очень большой, то для выяснения первого столбца матрицы можно использовать сортировку подсчетом, в этом случае алгоритм работает за действий и требует памяти, где — размер алфавита.Псевдокод оптимизированного алгоритмаПусть — количество символов во входной строке, — количество символов в алфавите, — номер исходной строки в матрице перестановок, — входящая строка, — массив для сортировки подсчетом, — вектор обратного преобразования, — номер данной нам строки в таблице.function reverseBWT(N : Int, M : Int, k : Int, s : Stirng): Int[] // Cчитаем частоты символов for i = 0 .. M count[i] = 0 for i = 0 .. N count[s[i]]++ // Упорядочиваем символы, чтобы получить первый столбец исходной матрицы // count[i] указывает на первую позицию символа i в первом столбце sum = 0 for i = 0 .. M sum = sum + count[i] count[i] = sum - count[i] // Cоздаем вектор обратного преобразования for i = 0 .. N t[count[s[i]]] = i count[s[i]]++ // И восстанавливаем исходный текст j = t[x] for i = 0 .. N answer[i] = s[j] j = t[j] return answer Доказательство корректностиПусть текст состоит из символов, занумерованных с нуля: . Буквы принадлежат некоторому алфавиту . Лексикографический порядок (строгий) на строках из алфавита будем обозначать . Обозначим через циклический сдвиг текста на символов влево:Существует перестановка чисел , которая удовлетворяет условию:Преобразование Барроуза-Уилера текста есть текст , буквы которого заданы соотношением:Пусть — перестановка чисел , удовлетворяющая условию:и в случае равенства и выполнено — . Перестановка однозначно определяется текстом и ее можно посчитать за , используя сортировку подсчетом. Рассмотрим перестановку как отображение . Пусть копмозиция отображений , где .
Алгоритм за линейное времяБудем обозначать -ую циклическую перестановку . Пусть , и , -- номер строки в таблице. Предподсчитаем следующие величины:
Пример для "BCABAAA":
Для удобства пронумеруем известные нам данные:
Символ находится в строке под номером , так как в таблице строка имела номер . Найдём символ .Символ имеет в строке тот же номер, что строка имела в таблице перестановок: строка начинается с символа , находится на 1 левее его и из-за циклического сдвига оказывается в последнем столбце. Нам известен символ . Посчитаем, на каком месте в таблице будет стоять строка, начинающаяся с этого символа.Из 4 известно количество символов, меньших . Все строки, начинающиеся с этих символов, стоят в таблице раньше . Кроме того, в таблице есть строки, начинающиеся с того же символа, что и . Из 3 известно, сколько их: если символ, равный , встречался в раньше, чем , то в таблице строка, начинающаяся с этого символа, тоже стоит раньше строки, начинающейся с , так как префикс строки, оканчивающейся на этот символ, меньше префикса строки, оканчивающейся на .Тогда сумма этих двух величин является номером символа в строке . Зная и , аналогично найдём .Предподсчёт занимает времени, восстановление каждого из символов занимает времени. Суммарное время работы алгоритма .Пример работы для "BCABAAA", 2 (нумерация с 0):
Дополнительно
См. такжеИсточники информацииПримечания |