Самый длинный палиндром в строке с использованием дерева суффиксов

Я пытался найти самый длинный палиндром в цепочке. Решение методом грубой силы занимает O (n ^ 3) времени. Я читал, что для этого есть алгоритм линейного времени, использующий суффиксные деревья. Я знаком с суффиксными деревьями и мне комфортно их строить. Как использовать построенное суффиксное дерево для поиска самого длинного палиндрома.


person shreyasva    schedule 12.08.2011    source источник
comment
Грубая сила занимает всего O (N ^ 2) времени.   -  person tskuzzy    schedule 12.08.2011
comment
Это не дубликат указанной выше ссылки. Попытайтесь понять вопрос. Ответы на приведенный выше вопрос дают в лучшем случае суперлинейный алгоритм без суффиксного дерева. Я ищу решение O (n) с использованием суффиксных деревьев.   -  person shreyasva    schedule 12.08.2011
comment
Итак, ваш вопрос больше похож на предположим, что я построил суффиксное дерево - как я могу использовать это дерево для поиска палиндромов? Это кажется связанным, но не дубликатом связанного вопроса.   -  person corsiKa    schedule 12.08.2011
comment
Я не могу проголосовать за повторное открытие, но это не дубликат !!! Это конкретный вопрос интервью, интересующийся сначала ожидает деревьев суффиксов (не имеет ничего общего с другим ответом) и интуитивного объяснения того, как это работает. Ни 100 строк кода, ни целая теория о том, как как можно быстрее найти палиндром в генетической последовательности из 10 миллиардов ACGT (johanjeuring.blogspot.com/2007/08/finding-palindromes.html) ...   -  person Ricky Bobby    schedule 13.08.2011
comment
Я тоже не могу голосовать, но ты прав. ни один из ответов в другом потоке не использует деревья суффиксов, afaict.   -  person andrew cooke    schedule 13.08.2011
comment
Повторно открылся после просмотра беседы в комментариях.   -  person Tim Post♦    schedule 13.08.2011
comment
@shreyasva Принятый ответ неверен. Пункты 3 и 4 не выполняются. Пожалуйста, откажитесь от ответа, чтобы его можно было удалить.   -  person Rikayan Bandyopadhyay    schedule 29.06.2014
comment
@RikayanBandyopadhyay, ты прав. Эти моменты изложены не очень хорошо. Но связанный документ хорош.   -  person cdunn2001    schedule 14.02.2015
comment
Грубая сила занимает ровно n * (n+1) * (n+2) / 6 (худший случай). Это O (N ^ 3)   -  person RaphaMex    schedule 01.05.2018


Ответы (5)


Я считаю, что вам нужно поступить следующим образом:

Пусть y 1 y 2 ... y n - ваша строка (где y i это буквы).

Создайте обобщенное суффиксное дерево S f = y 1 y 2 ... y n $ < / em> и S r = y n y n - 1 ... y 1 # < / em> (переверните буквы и выберите разные конечные символы для S f ($) и S r ( #)) ... где S f означает «Строка, вперед» и S r означает «Строка, обратная».

Для каждого суффикса i в S f найдите наименьшего общего предка с суффиксом n - i + 1 в S r.

То, что идет от корня до этого наименьшего общего предка, является палиндромом, потому что теперь наименьший общий предок представляет собой самый длинный общий префикс из этих двух суффиксов. Напомним, что:

(1) префикс суффикса - это подстрока.

(2) палиндром - это строка, идентичная своей обратной стороне.

(3) Таким образом, самый длинный палиндром в строке - это в точности самая длинная общая подстрока этой строки и ее обратной стороны.

(4) Таким образом, самый длинный палиндром в строке - это в точности самый длинный общий префикс из всех пар суффиксов между строкой и ее реверсом. Вот что мы здесь делаем.

ПРИМЕР

Возьмем слово банан.

S f = банан $

S r = ananab #

Ниже представлено обобщенное дерево суффиксов S f и S r, где число в конце каждого пути - индекс соответствующего суффикса. Произошла небольшая ошибка: a, общий для всех трех ветвей родительского элемента Blue_4, должен находиться на его входном крае, рядом с n:

введите описание изображения здесь

Самый нижний внутренний узел в дереве - это самая длинная общая подстрока этой строки и ее обратной стороны. Таким образом, глядя на все внутренние узлы дерева, вы найдете самый длинный палиндром.

Самый длинный палиндром находится между Green_0 и Blue_1 (т. Е. банан и anana) и составляет anana


ИЗМЕНИТЬ

Я только что нашел этот документ, который отвечает на этот вопрос.

person Ricky Bobby    schedule 12.08.2011
comment
Привет, как тебе удалось сделать этот потрясающий образ? Какой инструмент? - person Tomas; 13.08.2011
comment
@Tomas ага, это просто MS Powerpoint. это может быть очень полезно для такого рода рисования - person Ricky Bobby; 13.08.2011
comment
Меня просто интересует сложность этого подхода. Поскольку вам нужно обработать каждый суффикс, в худшем случае сложность времени и пространства будет O (n ^ 2). В этом случае это не лучше, чем перевернуть строку и найти самую длинную общую подпоследовательность. - person shreyasva; 08.09.2011
comment
@userccd, в худшем случае нужно проверять каждое ребро дерева, сложность должна быть O (numberOfNode) ~ O (n). - person Ricky Bobby; 08.09.2011
comment
В приведенном выше примере, почему ответ - Ана? разве это не анана? - person Sesh; 24.04.2012
comment
@Sesh Я не читал исправление, которое сделал Омар Отман, но ты прав. Все палиндромы - это пути от корня к внутреннему узлу. Следовательно, решение находится между зеленым 0 и синим 1 и является Анана. Я исправлю это как следует, когда у меня будет время. - person Ricky Bobby; 24.04.2012
comment
@ ricky-boby: Вы уверены в своем третьем и четвертом требованиях? Например, строка: xyztuvananakvutzyx и ее обратный xyztuvkananavutzyx имеют xyztuv как самый длинный общий префикс, но xyztuv не является равниной. - person CEGRD; 16.12.2012
comment
Исправьте, пожалуйста, этот ответ. Я думаю, вам просто нужно проверить, равна ли длина палиндрома плюс начальный индекс в прямой строке и начальный индекс в обратной строке длине исходной строки. - person Neil G; 16.01.2014
comment
@NeilG да, извините, я исправлю это в эти выходные. - person Ricky Bobby; 16.01.2014
comment
-1. Этот ответ неверен, как указал CEGRD. Утверждения 3 и 4 не выполняются. Вам следует серьезно исправить или удалить этот ответ. - person Thorkil Holm-Jacobsen; 26.04.2014
comment
В этом ответе есть изъян. - person zs2020; 12.02.2015
comment
п. 3 (и, следовательно, п. 4) неверно. Пример счетчика: самый длинный палиндром, содержащийся в строке abcdba, представляет собой одну букву, однако самая длинная общая подстрока abcdba и ее обратного abdcba - это ab (это 2 буквы). - person Ofer Magen; 09.09.2017
comment
Похоже, что для этого решения требуется LCA между любыми двумя узлами за время O (1). Я знаю, что можно вычислить структуру данных, которая даст ответы на такие вопросы, но это, конечно, нетривиально, поэтому мне интересно, следует ли об этом упоминать в этом ответе. - person piotrekg2; 05.12.2019

Линейное решение можно найти следующим образом:

Предварительные требования:

(1). Вы должны знать, как построить массив суффиксов за O (N) или O (NlogN) время.

(2). Вы должны знать, как найти стандартный массив LCP, т.е. LCP между соседними суффиксами i и i-1

т.е. LCP [i] = LCP (суффикс i в отсортированном массиве, суффикс i-1 в отсортированном массиве) для (i> 0).

Пусть S будет исходной строкой, а S ' будет обратной исходной строке. Возьмем, к примеру, S = "банан". Тогда его обратная строка S '= ananab.

Шаг 1: объедините S + # + S ', чтобы получить String Str, где # - это алфавит, отсутствующий в исходной String.

    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 не должен содержать # "ИЛИ" s2 должен содержать #, а s1 не должен содержать # ".

 |(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
person Ritesh Kumar Gupta    schedule 29.06.2012
comment
Я должен сказать удивительное объяснение .. Спасибо, это помогло мне решить проблему Spoj LPS - person ; 10.07.2012
comment
спасибо за объяснение, хотя для этого случая: 1234xaba4321, этот алгоритм выберет в результате 1234 или 4321 вместо aba? - person poiu2000; 28.03.2013
comment
@ poiu2000 Из текста: Условие if на шаге 4 в основном означает, что в каждой итерации (i), если я возьму суффиксы s1 (i) и s2 (i-1), тогда s1 должен содержать #, а s2 не должен содержать # ИЛИ s2 должен содержать #, а s1 не должен содержать # - person Cem; 23.08.2015
comment
Строго говоря, в этом ответе используется массив суффиксов, а не дерево суффиксов, которое на самом деле не отвечает на вопрос. - person pterodragon; 29.03.2019

С опозданием на несколько лет ...

Предположим, что s - исходная строка, а r - s перевернутая. Предположим также, что мы полностью построили суффиксное дерево ST, используя s.

Наш следующий шаг - проверить все суффиксы r на ST. С каждым новым суффиксом r мы будем вести подсчет первых k символов, которые мы успешно сопоставили с уже существующим суффиксом в дереве (т. Е. С одним из суффиксов s).

В качестве примера предположим, что мы сопоставляем суффикс "RAT" с r, а s содержал некоторые суффиксы, начинающиеся с "RA", но ни один из которых не соответствовал " КРЫСА ". k будет равно 2, когда нам, наконец, придется отказаться от надежды на последние символы "T". Мы сопоставили первые два символа суффикса r с первыми двумя символами суффикса s. Мы назовем этот узел, которого достигли, n.

А как мы узнаем, что нашли палиндром? Проверяя все конечные узлы под n.

В традиционном суффиксном дереве начальный индекс каждого суффикса хранится в конечном узле этой суффиксной ветви. В нашем примере выше s может содержать набор суффиксов, начинающихся с "RA", каждый из которых начинается с одного из индексов, присутствующих в потомках конечных узлов n.

Воспользуемся этими индексами.

Что это значит, если мы сопоставим k символов одной из подстрок R с k символами в ST? Ну, это просто означает, что мы обнаружили перевернутую строку. Но что это значит, если место, где начинается подстрока в R, совпадает с совпавшей подстрокой в ​​S плюс k? Да, это означает, что s[i] through s[i+k] читается так же, как s[i+k] through s[i]! Итак, по определению, мы обнаружили палиндром размером k.

Теперь все, что вам нужно сделать, это следить за самым длинным палиндромом, найденным на данный момент, и возвращать его в конце вашей функции.

person sgarza62    schedule 08.01.2015
comment
Не могли бы вы пояснить, почему предыдущие ответы неверны? - person templatetypedef; 08.01.2015
comment
@templatetypedef Посмотрите комментарии под каждым из них. В них есть контрпримеры. Я говорю о двух решениях, набравших наибольшее количество голосов. - person sgarza62; 08.01.2015
comment
Это очень простое решение и кажется правильным, но тогда почему другие ответы такие сложные? Даже от @zsoltsafrany, который описал решение из книги Skiena. - person max; 18.06.2017
comment
Я немного шокирован всеми положительными отзывами о неправильных ответах. Люди думают здесь перед голосованием? - person Amtrix; 10.01.2018
comment
Наконец-то правильный алгоритм с суффиксным деревом. И хорошее объяснение. - person RaphaMex; 01.05.2018
comment
Меня интересует сложность этого алгоритма. Постройте суффиксное дерево: O (n). Перечислить обратные суффиксы: O (n). Поместите каждый обратный суффикс в дерево: O (n). В общем, это даст O (n + n * n). Правильный? - person ngmir; 24.06.2018
comment
Проверка всех суффиксов r на ST стоит O (| r | ^ 2) времени - person pterodragon; 29.03.2019

Простое и краткое объяснение от Skiena - The Algorithm Design Manual

Найдите самый длинный палиндром в S [с помощью дерева суффиксов] - палиндром - это строка, которая читается одинаково, если порядок символов обратный, например мадам < / em>. Чтобы найти самый длинный палиндром в строке S, постройте единое суффиксное дерево, содержащее все суффиксы S и перестановку S, с каждым листом, идентифицируемым его начальной позицией. Палиндром определяется любым узлом в этом дереве, у которого есть прямые и обратные дочерние элементы из одной и той же позиции.

person Zsolt Safrany    schedule 01.11.2014

Решение 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;
}
person user3166594    schedule 06.01.2014
comment
Вопрос заключался в использовании суффиксного дерева не с DP. - person Zsolt Safrany; 01.11.2014