Самый длинный палиндром в строке с использованием дерева суффиксов
Я пытался найти самый длинный палиндром в строке. Решение грубой силы занимает O (n^3) времени. Я читал, что для него существует алгоритм линейного времени с использованием суффиксных деревьев. Я знаком с деревьями суффиксов и мне удобно их строить. Как вы используете построенное дерево суффиксов, чтобы найти самый длинный палиндром.
5 ответов
Я считаю, что нужно действовать таким образом:
пусть y1y2 ... yn быть строки (где yЯ письма).
создайте обобщенное дерево суффиксов Sf = y1y2 ... yn$ и Sr = ynyn-1 ... y1# (переверните буквы и выберите разные символы окончания для Sf ($) и Sr (#))... где Sf расшифровывается как "Строка", "Вперед" и Sr расшифровывается как "Строка, Обратный".
для каждого суффикса Я на Sf, найти наименьшего общего предка с суффиксом n-i + 1 на Sr.
что работает от корня до этого самого низкого общего предка палиндром, потому что теперь самый низкий общий предок представляет собой самый длинный общий префикс этих двух суффиксов. Вспомните, что:
(1) а префикс of a суффикс это подстрока.
(2) а палиндром - строка, идентичная ее обратной стороне.
(3) Таким образом, самый длинный содержащийся палиндром в строке является самой длинной общей подстрокой этой строки и ее обратной.
(4) таким образом, самый длинный палиндром в строке-это самый длинный общий префикс всех пар суффиксы между строкой и ее обратной. Вот что мы здесь делаем.
пример
давайте возьмем слово банан.
Sf = банан$
Sr = ananab#
Ниже приведено обобщенное дерево суффиксов Sf и Sr, где число в конце каждого пути является индекс соответствующего суффикса. Есть небольшая ошибка,a общие для всех 3 ветвей blue_4 родителя должны быть на его входящем краю, рядом с n:
низкий внутренний узел в дереве является самой длинной общей подстроки этой строки и наоборот. Глядя на все внутренние узлы дерево поэтому вы найдете самый длинный палиндром.
самый длинный палиндром находится между Green_0 и Blue_1 (т. е. банан и Анана) и Анана
EDIT
Я только что нашел этой статье это ответ на этот вопрос.
линейное решение можно найти следующим образом::
Prequisities:
(1).вы должны знать, как построить массив суффиксов в O(N) или O(NlogN) времени.
(2).вы должны знать, как найти стандартный массив LCP ie. LCP между смежными суффиксами i и i-1
ie . LCP [i]=LCP(суффикс i в отсортированном массиве, суффикс i-1 в отсортированном массиве) для (i>0).
пусть S будет Оригинальная строка и S' быть обратной исходной строки. Возьмем S="банан" как пример. Тогда его обратная строка S ' =ananab.
Шаг 1: Concatenate S + # + S' чтобы получить String Str, где # - алфавит, отсутствующий в исходной строке.
Concatenated String Str=S+#+S'
Str="banana#ananab"
Шаг 2: теперь построим массив суффиксов строки Str.
в этом примере массив суффиксов есть:
Suffix Number Index Sorted Suffix
0 6 #ananab
1 5 a#ananab
2 11 ab
3 3 ana#ananab
4 9 anab
5 1 anana#ananab
6 7 ananab
7 12 b
8 0 banana#ananab
9 4 na#ananab
10 10 nab
11 2 nana#ananab
12 8 nanab
обратите внимание, что массив суффиксов-это массив целых чисел, дающих начальные позиции суффиксов строки в лексикографическом порядке.Таким образом, массив, содержащий индекс начальной позиции, является массивом суффиксов.
что это SuffixArray[]={6,5,11,3,9,1,7,12,0,4,10,2,8};
Шаг 3: как вам удалось построить массив суффиксов, теперь найдите самые длинные общие префиксы между смежными суффиксы.
LCP between #ananab a#ananab is :=0
LCP between a#ananab ab is :=1
LCP between ab ana#ananab is :=1
LCP between ana#ananab anab is :=3
LCP between anab anana#ananab is :=3
LCP between anana#ananab ananab is :=5
LCP between ananab b is :=0
LCP between b banana#ananab is :=1
LCP between banana#ananab na#ananab is :=0
LCP between na#ananab nab is :=2
LCP between nab nana#ananab is :=2
LCP between nana#ananab nanab is :=4
таким образом, массив LCP LCP={0,0,1,1,3,3,5,0,1,0,2,2,4}.
где LCP[i]=длина самого длинного общего префикса между суффиксом i и суффиксом (i-1). (для i>0)
Шаг 4:
теперь, когда вы построили массив LCP, используйте следующую логику.
Let the length of the Longest Palindrome ,longestlength:=0 (Initially)
Let Position:=0.
for(int i=1;i<Len;++i)
{
//Note that Len=Length of Original String +"#"+ Reverse String
if((LCP[i]>longestlength))
{
//Note Actual Len=Length of original Input string .
if((suffixArray[i-1]<actuallen && suffixArray[i]>actuallen)||(suffixArray[i]<actuallen && suffixArray[i-1]>actuallen))
{
//print :Calculating Longest Prefixes b/w suffixArray[i-1] AND suffixArray[i]
longestlength=LCP[i];
//print The Longest Prefix b/w them is ..
//print The Length is :longestlength:=LCP[i];
Position=suffixArray[i];
}
}
}
So the length of Longest Palindrome :=longestlength;
and the longest palindrome is:=Str[position,position+longestlength-1];
Исполнение Пример:
actuallen=Length of banana:=6
Len=Length of "banana#ananab" :=13.
Calculating Longest Prefixes b/w a#ananab AND ab
The Longest Prefix b/w them is :a
The Length is :longestlength:= 1
Position:= 11
Calculating Longest Prefixes b/w ana#ananab AND anab
The Longest Prefix b/w them is :ana
The Length is :longestlength:= 3
Position:=9
Calculating Longest Prefixes b/w anana#ananab AND ananab
The Longest Prefix b/w them is :anana
The Length is :longestlength:= 5
Position:= 7
So Answer =5.
And the Longest Palindrome is :=Str[7,7+5-1]=anana
просто отметьте::
условие if на шаге 4 в основном это означает, что в каждой итерации (i), Если я беру суффиксы s1 (i) и s2(i-1), то"s1 должен содержать # и s2 не должен содержать #" или "С2 должны содержать # и С1 не содержит # ".
|(1:BANANA#ANANAB)|leaf
tree:|
| | | |(7:#ANANAB)|leaf
| | |(5:NA)|
| | | |(13:B)|leaf
| |(3:NA)|
| | |(7:#ANANAB)|leaf
| | |
| | |(13:B)|leaf
|(2:A)|
| |(7:#ANANAB)|leaf
| |
| |(13:B)|leaf
|
| | |(7:#ANANAB)|leaf
| |(5:NA)|
| | |(13:B)|leaf
|(3:NA)|
| |(7:#ANANAB)|leaf
| |
| |(13:B)|leaf
|
|(7:#ANANAB)|leaf
С опозданием на несколько лет...
предположим s
является исходной строкой, и r
is s
отменено. Предположим также, что мы полностью построили дерево суффиксов ST
используя s
.
наш следующий шаг-проверить все суффиксы r
против ST
. С каждым новым суффиксом r
, мы будем поддерживать счет первого k
символы, которые мы успешно сопоставили с уже существующим суффиксом в дереве (т. е. одним из s
'ы суффиксы.)
в качестве примера, скажем, мы сопоставляем суффикс "крыса" С r
и s
содержит некоторые суффиксы начиная с "РА", но ни один из них не соответствовал "крыса". k
будет равно 2, когда нам, наконец, пришлось отказаться от надежды на окончательные символы "Т". Мы сопоставили первые два символа r
суффикс с первыми двумя символами s
суффикса-ов. Мы назовем этот узел, который мы достигли n
.
n
.
в традиционном дереве суффиксов начальный индекс каждого суффикса хранится в узле листа этой ветви суффикса. В нашем примере выше, s
возможно, содержит кучу суффиксов, начинающихся с "РА", каждый из которых начинается с одного из индексов, присутствующих в потомках листового узла n
.
давайте использовать эти индексы.
что это значит, если мы Матч k
героев R
подстроки против k
символы ST
? Ну, это просто значит, что мы нашли какую-то обратную струну. Но что это значит, если место, где начинается подстрока в R
равна подстроку в S
плюс k
? Да, это значит s[i] through s[i+k]
читается так же, как s[i+k] through s[i]
! И так, be definition мы обнаружили палиндром размер k
.
теперь все, что вам нужно сделать, это сохранить вкладку на самом длинном палиндроме, найденном до сих пор, и вернуть его в конце вашей функции.
простое и короткое объяснение от Skiena - The Algorithm Design Manual
найти самый длинный палиндром в S [с помощью суффиксного дерева] - A палиндром - это строка, которая читает то же самое, если порядок символов отменен, например мадам. Чтобы найти самый длинный палиндром в строке S, постройте одно дерево суффиксов, содержащее все суффиксы S и разворот S, с каждым листом, идентифицированным по его начальной позиции. Палиндром определяется любым узлом в этом дереве что вперед и вспять дети с той же позиции.
решение DP:
int longestPalin(char *str)
{
n = strlen(str);
bool table[n][n]l
memset(table, 0, sizeof(table));
int start = 0;
for(int i=0; i<n; ++i)
table[i][i] = true;
int maxlen = 1;
for(int i=0; i<n-1; ++i)
{
if(str[i] == str[i+1])
{
table[i][i] = true;
start = i;
maxlen = 2;
}
}
for(int k=3; k<=n; ++k)
{
for(int i=0; i<n-k+1; ++i)
{
int j = n+k-1;
if(str[i] == str[j] && table[i+1][j-1])
{
table[i][j] = true;
if(k > maxlen)
{
start = i;
maxlen = k;
}
}
}
}
print(str, start, start+maxlen-1);
return maxlen;
}