web-dev-qa-db-fra.com

Algorithme de Manacher (algorithme pour trouver la plus longue sous-chaîne palindrome en temps linéaire)

Après avoir passé environ 6 à 8 heures à essayer de digérer l'algorithme de Manacher, je suis prêt à jeter l'éponge. Mais avant de le faire, voici un dernier coup dans le noir: quelqu'un peut-il l'expliquer? Je me fiche du code. Je veux que quelqu'un explique l'algorithme [~ # ~] [~ # ~] .

Ici semble être un endroit que les autres semblent apprécier pour expliquer l'algorithme: http://www.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

Je comprends pourquoi vous voudriez transformer la chaîne, disons, 'abba' en # a # b # b # a # Après que je sois perdu. Par exemple, l'auteur du site Web mentionné précédemment dit que l'élément clé de l'algorithme est:

                      if P[ i' ] ≤ R – i,
                      then P[ i ] ← P[ i' ]
                      else P[ i ] ≥ P[ i' ]. (Which we have to expand past 
                      the right Edge (R) to find P[ i ])

Cela semble faux, car il/elle dit à un moment donné que P [i] est égal à 5 ​​lorsque P [i '] = 7 et P [i] n'est pas inférieur ou égal à R - i.

Si vous n'êtes pas familier avec l'algorithme, voici quelques liens supplémentaires: http://tristan-interview.blogspot.com/2011/11/longest-palindrome-substring-manachers.html (I ' J'ai essayé celui-ci, mais la terminologie est horrible et déroutante. Tout d'abord, certaines choses ne sont pas définies. De plus, trop de variables. Vous avez besoin d'une liste de contrôle pour vous rappeler quelle variable fait référence à quoi.)

Un autre est: http://www.akalin.cx/longest-palindrome-linear-time (bonne chance)

L'essentiel de l'algorithme est de trouver le palindrome le plus long en temps linéaire. Cela peut être fait en O (n ^ 2) avec un effort minimum à moyen. Cet algorithme est censé être assez "intelligent" pour le ramener à O (n).

68
user678392

Je suis d'accord que la logique n'est pas tout à fait correcte dans l'explication du lien. Je donne quelques détails ci-dessous.

L'algorithme de Manacher remplit un tableau P [i] qui contient jusqu'où s'étend le palindrome centré en i. Si P [5] = 3, alors trois caractères de chaque côté de la position cinq font partie du palindrome. L'algorithme tire parti du fait que si vous avez trouvé un long palindrome, vous pouvez remplir rapidement les valeurs de P sur le côté droit du palindrome en regardant les valeurs de P sur le côté gauche, car elles devraient principalement être les même.

Je vais commencer par expliquer le cas dont vous parliez, puis je développerai cette réponse au besoin.

R indique l'indice du côté droit du palindrome centré en C. Voici l'état à l'endroit que vous avez indiqué:

C=11
R=20
i=15
i'=7
P[i']=7
R-i=5

et la logique est la suivante:

if P[i']<=R-i:  // not true
else: // P[i] is at least 5, but may be greater

Le pseudo-code dans le lien indique que P [i] devrait être supérieur ou égal à P [i '] si le test échoue, mais je pense qu'il devrait être supérieur ou égal à R-i, et l'explication le confirme.

Puisque P [i '] est supérieur à Ri, le palindrome centré en i' s'étend au-delà du palindrome centré en C. Nous savons que le palindrome centré en i aura au moins Ri caractères larges, car nous avons encore une symétrie jusqu'à ce point, mais nous devons chercher explicitement au-delà de cela.

Si P [i '] n'avait pas été supérieur à Ri, alors le plus grand palindrome centré en i' se trouve dans le plus grand palindrome centré en C, nous aurions donc su que P [i] ne pouvait pas être plus grand que P [i ']. Si c'était le cas, nous aurions une contradiction. Cela signifierait que nous pourrions étendre le palindrome centré en i au-delà de P [i '], mais si nous le pouvions, nous pourrions également étendre le palindrome centré en i' en raison de la symétrie, mais c'était déjà censé être aussi grand que possible.

Ce cas est illustré précédemment:

C=11
R=20
i=13
i'=9
P[i']=1
R-i=7

Dans ce cas, P [i '] <= R-i. Puisque nous sommes encore à 7 caractères du bord du palindrome centré en C, nous savons qu'au moins 7 caractères autour de i sont les mêmes que les 7 caractères autour de i '. Puisqu'il n'y avait qu'un palindrome à un caractère autour de i ', il y a aussi un palindrome à un caractère autour de i.

j_random_hacker a remarqué que la logique devrait être plus comme ceci:

if P[i']<R-i then
  P[i]=P[i']
else if P[i']>R-i then
  P[i]=R-i
else P[i]=R-i + expansion

Si P [i '] <R-i, alors nous savons que P [i] == P [i'], puisque nous sommes toujours à l'intérieur du palindrome centré en C.

Si P [i ']> R-i, alors nous savons que P [i] == R-i, car sinon le palindrome centré en C aurait dépassé R.

Donc l'expansion n'est vraiment nécessaire que dans le cas spécial où P [i '] == R-i, donc nous ne savons pas si le palindrome à P [i] peut être plus long.

Ceci est géré dans le code réel en définissant P [i] = min (P [i '], R-i) puis en développant toujours. Cette façon de procéder n'augmente pas la complexité temporelle, car si aucune expansion n'est nécessaire, le temps nécessaire pour effectuer l'expansion est constant.

38
Vaughn Cato

L'algorithme sur ce site semble compréhensible jusqu'à un certain point http://www.akalin.cx/longest-palindrome-linear-time

Pour comprendre cette approche particulière, le mieux est d'essayer de résoudre le problème sur papier et de saisir les astuces que vous pouvez mettre en œuvre pour éviter de vérifier le palindrome pour chaque centre possible.

Répondez d'abord vous-même - lorsque vous trouvez un palindrome d'une longueur donnée, disons 5 - ne pouvez-vous pas, comme prochaine étape, simplement sauter à la fin de ce palindrome (sauter 4 lettres et 4 lettres médianes)?

Si vous essayez de créer un palindrome de longueur 8 et placez un autre palindrome de longueur> 8, dont le centre se trouve sur le côté droit du premier palindrome, vous remarquerez quelque chose de drôle. Essayez-le: Palindrome de longueur 8 - WOWILIKEEKIL - Comme + ekiL = 8 Maintenant, dans la plupart des cas, vous pourriez écrire la place entre deux E comme centre et le nombre 8 comme longueur et sauter après le dernier L à rechercher le centre du plus grand palindrome.

Cette approche n'est pas correcte, le centre du plus grand palindrome peut être à l'intérieur de ekiL et vous le rateriez si vous sautiez après le dernier L.

Après avoir trouvé LIKE + EKIL, vous placez 8 dans le tableau que ces algos utilisent et cela ressemble à ceci:

[0,1,0,3,0,1,0,1,0,3,0,1,0,1,0,1,8]

for

[#,WOW J'AIME,#]

L'astuce est que vous savez déjà que les 7 prochains numéros (8-1) après 8 seront probablement les mêmes que sur le côté gauche, donc l'étape suivante consiste à copier automatiquement 7 numéros de la gauche de 8 à la droite de 8 en gardant l'esprit qu'ils ne sont pas encore définitifs. Le tableau ressemblerait à ceci

[0,1,0,3,0,1,0,1,0,3,0,1,0,1,0,1,8,1,0,1,0,1,0,3] ( nous sommes à 8)

for

[#, W, #, O, #, W, #, I, #, L, #, I, #, K, #, E, #, E, #, K, #, I, #, L]

Prenons un exemple, qu'un tel saut détruirait notre solution actuelle et voyons ce que nous pouvons remarquer.

WOWILIKEEKIL - permet d'essayer de faire un plus grand palindrome avec le centre quelque part dans EKIL. Mais ce n'est pas possible - nous devons changer Word EKIL en quelque chose qui contient palindrome. Quelle? OOOOOh - c'est l'astuce. La seule possibilité d'avoir un palindrome plus grand avec le centre du côté droit de notre palindrome actuel est qu'il est déjà du côté droit (et gauche) du palindrome.

Essayons d'en construire un basé sur WOWILIKEEKIL Nous aurions besoin de changer EKIL par exemple EKIK avec I comme centre du plus grand palindrome - n'oubliez pas de changer LIKE en KIKE également. Les premières lettres de notre palindrome délicat seront:

WOWIKIKEEKIK

comme dit précédemment - que le dernier soit le centre du plus grand pallindrome que KIKEEKIK:

WOWIKIKEEKIKEEKIKIW

faisons le tableau jusqu'à notre ancien pallindrom et découvrons comment tirer parti des informations supplémentaires.

for

[_ W _ O _ W _ I _ K _ I _ K _ E _ E _ K _ I _ K _ E _ E _ K _ I _ K _ I _ W]

ce sera [0,1,0,3,0,1,0,1,0,3,0,3,0,1,0,1,8

nous savons que le prochain I - un 3e sera le plus long pallindrome, mais oublions-le un peu. permet de copier les nombres dans le tableau de la gauche de 8 vers la droite (8 nombres)

[0,1,0,3,0,1,0,1,0,3,0,3,0,1,0,1,8,1,0,1,0,3,0,3]

Dans notre boucle, nous sommes entre E avec le numéro 8. Quelle est la particularité de I (futur milieu du plus grand pallindrome) que nous ne pouvons pas sauter directement à K (la dernière lettre du plus grand pallindrome actuellement)? La particularité est qu'elle dépasse la taille actuelle du tableau ... comment? Si vous déplacez 3 espaces vers la droite de 3 - vous êtes hors du tableau. Cela signifie qu'il peut être au milieu du plus grand pallindrome et le plus loin que vous pouvez sauter est cette lettre I.

Désolé pour la longueur de cette réponse - je voulais expliquer l'algorithme et je peux vous assurer - @OmnipotentEntity avait raison - je le comprends encore mieux après vous avoir expliqué :)

12
Jacek Serafinski

J'ai trouvé l'une des meilleures explications à ce jour sur le lien suivant:

http://tarokuriyama.com/projects/palindrome2.php

Il a également une visualisation pour le même exemple de chaîne (babcbabcbaccba) utilisé au premier lien mentionné dans la question.

En dehors de ce lien, j'ai également trouvé le code sur

http://algs4.cs.princeton.edu/53substring/Manacher.Java.html

J'espère que cela sera utile à d'autres qui s'efforcent de comprendre le nœud de cet algorithme.

11
scv

Article complet: http://www.zrzahid.com/longest-palindromic-substring-in-linear-time-manachers-algorithm/

Tout d'abord, observons de près un palindrome afin de trouver des propriétés intéressantes. Par exemple, S1 = "abaaba" et S2 = "abcba", les deux sont palindromes mais quelle est la différence non triviale (c'est-à-dire pas de longueur ou de caractères) entre eux? S1 est un palindrome centré autour de l'espace invisible entre i = 2 et i = 3 (espace inexistant!). D'un autre côté, S2 est centré autour du caractère en i = 2 (c'est-à-dire c). Afin de gérer gracieusement le centre d'un palindrome quelle que soit la longueur paire/impaire, permet de transformer le palindrome en insérant un caractère spécial $ entre les caractères. Alors S1 = "abba" et S2 = "abcba" seront transformés en T1 = "$ a $ b $ a $ a $ b $ a $" centré en i = 6 et T2 = "$ a $ b $ c $ b $ a $ "centré sur i = 5. Maintenant, nous pouvons voir que les centres existent et que les longueurs sont cohérentes 2 * n + 1, où n = longueur de la chaîne d'origine. Par exemple,

 i 'ci 
 ------------------------------------- ---------------- 
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 
 ------------------------------------------- ---------- 
 T1 = | $ | a | $ | b | $ | a | $ | a | $ | b | $ | a | $ | 
 ------------------------------------------- ---------- 

Ensuite, observez qu'à partir de la propriété symétrique d'un palindrome (transformé) T autour du centre c, T [c-k] = T [c + k] pour 0 <= k <= c. Autrement dit, les positions c-k et c + k sont symétriques l'une de l'autre. Autrement dit, pour un indice i à droite du centre c, l'indice miroir i 'est à gauche de c tel que c-i' = i-c => i '= 2 * c-i et vice versa. C'est,

Pour chaque position i à droite du centre c d'une sous-chaîne palindromique, la position miroir de i est, i '= 2 * c-i, et vice versa.

Définissons un tableau P [0..2 * n] tel que P [i] soit égal à la longueur du palindrome centré en i. Notez que la longueur est réellement mesurée par le nombre de caractères dans la chaîne d'origine (en ignorant les caractères spéciaux $). Soit également min et max respectivement la limite la plus à gauche et la plus à droite d'une sous-chaîne palindromique centrée en c. Donc, min = c-P [c] et max = c + P [c]. Par exemple, pour le palindrome S = "abaaba", le palindrome transformé T, centre du miroir c = 6, tableau de longueurs P [0..12], min = cP [c] = 6-6 = 0, max = c + P [c] = 6 + 6 = 12 et deux exemples d'indices miroir i et i 'sont illustrés dans la figure suivante.

 min i 'ci max 
 ----------------------------------- ------------------ 
 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 
 ------------------------------------------- ---------- 
 T = | $ | a | $ | b | $ | a | $ | a | $ | b | $ | a | $ | 
 ------------------------------------------- ---------- 
 P = | 0 | 1 | 0 | 3 | 0 | 5 | 6 | 1 | 0 | 3 | 0 | 1 | 0 | 
 ------------------------------------------- ---------- 

Avec un tel tableau de longueur P, nous pouvons trouver la longueur de la plus longue sous-chaîne palindromique en regardant l'élément max de P. C'est-à-dire,

P [i] est la longueur d'une sous-chaîne palindromique de centre en i dans la chaîne transformée T, c'est-à-dire. centre à i/2 dans la chaîne originale S; Par conséquent, la sous-chaîne palindromique la plus longue serait la sous-chaîne de longueur P [imax] à partir de l'index (imax-Pimax])/2 tel que imax est l'indice de l'élément maximal dans P.

Tirons une figure similaire dans ce qui suit pour notre exemple de chaîne non palindromique S = "babaabca".

 min c max 
 | ---------------- | ----------------- | 
 ---------------------------------------------- ---------------------- 
 idx = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 
 ------------------------------------------- -------------------------- 
 T = | $ | b | $ | a | $ | b | $ | a | $ | a | $ | b | $ | c | $ | a | $ | 
 ------------------------------------------- -------------------------- 
 P = | 0 | 1 | 0 | 3 | 0 | 3 | 0 | 1 | 4 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 
 ------------------------------------------- -------------------------- 

La question est de savoir comment calculer P efficacement. La propriété symétrique suggère les cas suivants que nous pourrions potentiellement utiliser pour calculer P [i] en utilisant P [i '] précédemment calculé à l'index miroir i' sur la gauche, sautant ainsi de nombreux calculs. Supposons que nous ayons un palindrome de référence (premier palindrome) pour commencer.

  1. Un troisième palindrome dont le centre se trouve dans le côté droit d'un premier palindrome aura exactement la même longueur que celui d'un deuxième palindrome ancré au centre du miroir sur le côté gauche, si le deuxième palindrome se trouve dans les limites du premier palindrome par au moins au moins un caractère.
    Par exemple dans la figure suivante avec le premier palindrome centré à c = 8 et délimité par min = 4 et max = 12, longueur du troisième palindrome centré à i = 9 (avec indice de miroir i '= 2 * ci = 7) est, P [i] = P [i '] = 1. En effet, le deuxième palindrome centré en i' est dans les limites du premier palindrome. De même, P [10] = P [6] = 0.
     
     
     | ---- 3e ---- | 
     | ---- 2e ---- | 
     | ----------- 1er Palindrome --------- | 
     Min i 'ci max 
     | ----- ------- | --- | --- | ------------- | 
     --------------- -------------------------------------------------- --- 
     idx = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 
     ------------------------------------------- -------------------------- 
     T = | $ | b | $ | a | $ | b | $ | a | $ | a | $ | b | $ | c | $ | a | $ | 
     ------------------------------------------- -------------------------- 
     P = | 0 | 1 | 0 | 3 | 0 | 3 | 0 | 1 | 4 | ? | ? | ? | ? | ? | ? | ? | ? | 
     -------------------------------------------- ------------------------- 
    
    Maintenant, la question est de savoir comment vérifier ce cas? Notez qu'en raison de la propriété symétrique, la longueur du segment [min..i '] est égale à la longueur du segment [i..max]. Notez également que le 2e palindrome est complètement à l'intérieur du 1er palindrome si à gauche Le bord du 2e palindrome se trouve à l'intérieur de la limite gauche, min du 1er palindrome. C'est,
     
     i'-P [i ']> = min 
     => P [i'] - i '<-min (négation) 
     => P [i '] <i'-min 
     => P [i'] <max-i [(max-i) = (i'-min) en raison de la propriété symétrique]. 
    
    Combinant tous les faits dans le cas 1,
    P [i] = P [i '], ssi (max-i)> P [i']
  2. Si le deuxième palindrome rencontre ou s'étend au-delà de la limite gauche du premier palindrome, alors le troisième palindrome est garanti pour avoir au moins la longueur de son propre centre au caractère le plus à l'extérieur droit du premier palindrome. Cette longueur est la même du centre du deuxième palindrome au caractère le plus à gauche du premier palindrome.
    Par exemple dans la figure suivante, le deuxième palindrome centré à i = 5 s'étend au-delà de la limite gauche du premier palindrome. Donc, dans ce cas, nous ne pouvons pas dire P [i] = P [i ']. Mais la longueur du troisième palindrome centré en i = 11, P [i] est au moins la longueur de son centre i = 11 jusqu'à la limite droite max = 12 du premier palindrome centré en c. Autrement dit, P [i]> = 1. Cela signifie que le troisième palindrome pourrait être étendu au-delà de max si et seulement si le prochain caractère immédiat passé max correspond exactement au personnage en miroir, et nous continuons cette vérification au-delà. Par exemple, dans ce cas P [13]! = P [9] et il ne peut pas être étendu. Donc, P [i] = 1.
                                                        
     | ------- 2e palindrome ------ | | ---- 3e ---- | ---? 
     | ----------- 1er Palindrome --------- | 
     Min i 'ci max 
     | ---- | ----------- | ----------- | ----- | 
     --------------- -------------------------------------------------- --- 
     idx = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 
     ------------------------------------------- -------------------------- 
     T = | $ | b | $ | a | $ | b | $ | a | $ | a | $ | b | $ | c | $ | a | $ | 
     ------------------------------------------- -------------------------- 
     P = | 0 | 1 | 0 | 3 | 0 | 3 | 0 | 1 | 4 | 1 | 0 | ? | ? | ? | ? | ? | ? | 
     -------------------------------------------- ------------------------- 
    
    Alors, comment vérifier ce cas? Il s'agit simplement de l'échec de la vérification du cas 1. Autrement dit, le deuxième palindrome s'étendra au-delà du bord gauche du premier palindrome si,
     
     i'-P [i '] <min 
     => P [i'] - i '> = -min [nier] 
     => P [i ']> = i'-min 
     => P [i']> = max-i [(max-i) = (i'-min) en raison de la propriété symétrique]. 
    
    Autrement dit, P [i] est au moins (max-i) ssi (max-i) P [i]> = (max-i), ssi (max-i) Maintenant, si le troisième palindrome ne dépasse pas max alors nous devons mettre à jour le centre et la limite du nouveau palindrome.
    Si le palindrome centré en i s'étend au-delà de max, alors nous avons un nouveau palindrome (étendu), donc un nouveau centre en c = i. Mettre à jour max à la limite la plus à droite du nouveau palindrome.
    En combinant tous les faits des cas 1 et 2, nous pouvons proposer de très belles petites formules:
     
     Cas 1: P [i] = P [i '], ssi (max-i)> P [i'] 
     Cas 2: P [i]> = (max-i), ssi (max-i) = min (P [i '], max-i). 
    
    Autrement dit, P [i] = min (P [i '], max-i) lorsque le troisième palindrome n'est pas extensible au-delà de max. Sinon, nous avons un nouveau troisième palindrome au centre à c = i et un nouveau max = i + P [i].
  3. Ni le premier ni le deuxième palindrome ne fournissent des informations permettant de déterminer la longueur palindromique d'un quatrième palindrome dont le centre est à l'extérieur du côté droit du premier palindrome.
    Autrement dit, nous ne pouvons pas déterminer de manière préventive P [i] si i> max. C'est,
    P [i] = 0, ssi max-i <0
    En combinant tous les cas, nous concluons les formules:
    P [i] = max> i? min (P [i '], max-i): 0. Dans le cas où nous pouvons développer au-delà de max, nous développons en faisant correspondre les caractères au-delà de max avec le caractère en miroir par rapport au nouveau centre à c = i. Enfin, lorsque nous avons un décalage, nous mettons à jour le nouveau max = i + P [i].

Référence: description de l'algorithme dans la page wiki

5
user3674869

J'ai fait une vidéo sur cet algorithme en utilisant des graphiques d'animation. J'espère que cela vous aidera à le comprendre! https://www.youtube.com/watch?v=kbUiR5YWUpQ

1
Quinston Pimenta

Ce matériel est d'une grande aide pour moi de le comprendre: http://solutionleetcode.blogspot.com/2013/07/leetcode-longest-palindromic-substring.html

Définissez T comme la longueur des sous-chaînes palindromiques les plus longues centrées sur chacun des caractères.

L'essentiel est que, lorsque des palindromes plus petits sont complètement intégrés dans le palindrome plus long, T [i] doit également être symétrique dans le palindrome plus long.

Sinon, nous devrons calculer T [i] à partir de zéro, plutôt que d'induire à partir de la partie gauche symétrique.

1
Lin Jian

Solution Javascript rapide pour trouver le palindrome le plus long d'une chaîne:

const lpal = str => {
  let lpal = ""; // to store longest palindrome encountered
  let pal = ""; // to store new palindromes found
  let left; // to iterate through left side indices of the character considered to be center of palindrome
  let right; // to iterate through left side indices of the character considered to be center of palindrome
  let j; // to iterate through all characters and considering each to be center of palindrome
  for (let i=0; i<str.length; i++) { // run through all characters considering them center of palindrome
    pal = str[i]; // initializing current palindrome
    j = i; // setting j as index at the center of palindorme
    left = j-1; // taking left index of j
    right = j+1; // taking right index of j
    while (left >= 0 && right < str.length) { // while left and right indices exist
      if(str[left] === str[right]) { //
        pal = str[left] + pal + str[right];
      } else {
        break;
      }
      left--;
      right++;
    }
    if(pal.length > lpal.length) {
      lpal = pal;
    }
    pal = str[i];
    j = i;
    left = j-1;
    right = j+1;
    if(str[j] === str[right]) {
      pal = pal + str[right];
      right++;
      while (left >= 0 && right < str.length) {
        if(str[left] === str[right]) {
          pal = str[left] + pal + str[right];
        } else {
          break;
        }
        left--;
        right++;
      }
      if(pal.length > lpal.length) {
        lpal = pal;
      }
    }
  }
  return lpal;
}

Exemple d'entrée

console.log(lpal("gerngehgbrgregbeuhgurhuygbhsbjsrhfesasdfffdsajkjsrngkjbsrjgrsbjvhbvhbvhsbrfhrsbfsuhbvsuhbvhvbksbrkvkjb"));

Sortie

asdfffdsa
0
Vinit Khandelwal
class Palindrome
{
    private int center;
    private int radius;

    public Palindrome(int center, int radius)
    {
        if (radius < 0 || radius > center)
            throw new Exception("Invalid palindrome.");

        this.center = center;
        this.radius = radius;
    }

    public int GetMirror(int index)
    {
        int i = 2 * center - index;

        if (i < 0)
            return 0;

        return i;
    }

    public int GetCenter()
    {
        return center;
    }

    public int GetLength()
    {
        return 2 * radius;
    }

    public int GetRight()
    {
        return center + radius;
    }

    public int GetLeft()
    {
        return center - radius;
    }

    public void Expand()
    {
        ++radius;
    }

    public bool LargerThan(Palindrome other)
    {
        if (other == null)
            return false;

        return (radius > other.radius);
    }

}

private static string GetFormatted(string original)
{
    if (original == null)
        return null;
    else if (original.Length == 0)
        return "";

    StringBuilder builder = new StringBuilder("#");
    foreach (char c in original)
    {
        builder.Append(c);
        builder.Append('#');
    }

    return builder.ToString();
}

private static string GetUnFormatted(string formatted)
{
    if (formatted == null)
        return null;
    else if (formatted.Length == 0)
        return "";

    StringBuilder builder = new StringBuilder();
    foreach (char c in formatted)
    {
        if (c != '#')
            builder.Append(c);
    }

    return builder.ToString();
}

public static string FindLargestPalindrome(string str)
{
    string formatted = GetFormatted(str);

    if (formatted == null || formatted.Length == 0)
        return formatted;

    int[] radius = new int[formatted.Length];

    try
    {
        Palindrome current = new Palindrome(0, 0);
        for (int i = 0; i < formatted.Length; ++i)
        {
            radius[i] = (current.GetRight() > i) ?
                Math.Min(current.GetRight() - i, radius[current.GetMirror(i)]) : 0;

            current = new Palindrome(i, radius[i]);

            while (current.GetLeft() - 1 >= 0 && current.GetRight() + 1 < formatted.Length &&
                formatted[current.GetLeft() - 1] == formatted[current.GetRight() + 1])
            {
                current.Expand();
                ++radius[i];
            }
        }

        Palindrome largest = new Palindrome(0, 0);
        for (int i = 0; i < radius.Length; ++i)
        {
            current = new Palindrome(i, radius[i]);
            if (current.LargerThan(largest))
                largest = current;
        }

        return GetUnFormatted(formatted.Substring(largest.GetLeft(), largest.GetLength()));
    }
    catch (Exception ex) 
    {
        Console.WriteLine(ex);
    }

    return null;
}
0
Gevorg Meliksetyan