Algoritmo de Manacher – Substring palindrómica más larga de tiempo lineal – Parte 3

En Algoritmo de Manacher Parte 1 y Parte 2 , repasamos algunos de los conceptos básicos, entendimos la array de longitud LPS y cómo calcularla de manera eficiente en base a cuatro casos. Aquí implementaremos lo mismo.
Hemos visto que no se necesitan nuevas comparaciones de caracteres en el caso 1 y el caso 2. En los casos 3 y 4, se necesitan nuevas comparaciones necesarias. 
En la siguiente figura, 

Manacher's Algorithm – Linear Time Longest Palindromic Substring

Si necesitamos una comparación, solo compararemos los caracteres reales, que están en posiciones «impares» como 1, 3, 5, 7, etc. 
Las posiciones pares no representan un carácter en la string, por lo que no se realizará ninguna comparación para incluso posiciones. 
Si dos caracteres en diferentes posiciones impares coinciden, aumentarán la longitud de LPS en 2.

Hay muchas formas de implementar esto dependiendo de cómo se manejen las posiciones pares e impares. Una forma sería crear una nueva string primero donde insertamos algún carácter único (por ejemplo, #, $, etc.) en todas las posiciones pares y luego ejecutar el algoritmo en eso (para evitar diferentes formas de manejo de posiciones pares e impares). Otra forma podría ser trabajar en la string dada, pero aquí las posiciones pares e impares deben manejarse adecuadamente.

Aquí comenzaremos con la string dada en sí. Cuando haya una necesidad de expansión y se requiera una comparación de caracteres, expandiremos en las posiciones izquierda y derecha una por una. Cuando se encuentre una posición impar, se realizará una comparación y la longitud LPS se incrementará en UNO. Cuando se encuentra una posición par, no se realiza ninguna comparación y la longitud de LPS se incrementará en UNO (por lo tanto, en general, una posición impar y una par en los lados izquierdo y derecho aumentarán la longitud de LPS en DOS).

Implementación:

C

// A C program to implement Manacher’s Algorithm
#include <stdio.h>
#include <string.h>
 
char text[100];
void findLongestPalindromicString()
{
    int N = strlen(text);
    if(N == 0)
        return;
    N = 2*N + 1; //Position count
    int L[N]; //LPS Length Array
    L[0] = 0;
    L[1] = 1;
    int C = 1; //centerPosition
    int R = 2; //centerRightPosition
    int i = 0; //currentRightPosition
    int iMirror; //currentLeftPosition
    int expand = -1;
    int diff = -1;
    int maxLPSLength = 0;
    int maxLPSCenterPosition = 0;
    int start = -1;
    int end = -1;
     
    //Uncomment it to print LPS Length array
    //printf("%d %d ", L[0], L[1]);
    for (i = 2; i < N; i++)
    {
        //get currentLeftPosition iMirror for currentRightPosition i
        iMirror = 2*C-i;
        //Reset expand - means no expansion required
        expand = 0;
        diff = R - i;
        //If currentRightPosition i is within centerRightPosition R
        if(diff >= 0)
        {
            if(L[iMirror] < diff) // Case 1
                L[i] = L[iMirror];
            else if(L[iMirror] == diff && R == N-1) // Case 2
                L[i] = L[iMirror];
            else if(L[iMirror] == diff && R < N-1) // Case 3
            {
                    L[i] = L[iMirror];
                    expand = 1; // expansion required
            }
            else if(L[iMirror] > diff) // Case 4
            {
                L[i] = diff;
                expand = 1; // expansion required
            }
        }
        else
        {
            L[i] = 0;
            expand = 1; // expansion required
        }
         
        if (expand == 1)
        {
            //Attempt to expand palindrome centered at currentRightPosition i
            //Here for odd positions, we compare characters and
            //if match then increment LPS Length by ONE
            //If even position, we just increment LPS by ONE without
            //any character comparison
            while (((i + L[i]) < N && (i - L[i]) > 0) &&
                ( ((i + L[i] + 1) % 2 == 0) ||
                (text[(i + L[i] + 1)/2] == text[(i-L[i]-1)/2] )))
            {
                L[i]++;
            }
        }
 
        if(L[i] > maxLPSLength) // Track maxLPSLength
        {
            maxLPSLength = L[i];
            maxLPSCenterPosition = i;
        }
 
        // If palindrome centered at currentRightPosition i
        // expand beyond centerRightPosition R,
        // adjust centerPosition C based on expanded palindrome.
        if (i + L[i] > R)
        {
            C = i;
            R = i + L[i];
        }
        //Uncomment it to print LPS Length array
        //printf("%d ", L[i]);
    }
    //printf("\n");
    start = (maxLPSCenterPosition - maxLPSLength)/2;
    end = start + maxLPSLength - 1;
    //printf("start: %d end: %d\n", start, end);
    printf("LPS of string is %s : ", text);
    for(i=start; i<=end; i++)
        printf("%c", text[i]);
    printf("\n");
}
 
 
int main(int argc, char *argv[])
{
 
    strcpy(text, "babcbabcbaccba");
    findLongestPalindromicString();
 
    strcpy(text, "abaaba");
    findLongestPalindromicString();
 
    strcpy(text, "abababa");
    findLongestPalindromicString();
 
    strcpy(text, "abcbabcbabcba");
    findLongestPalindromicString();
 
    strcpy(text, "forgeeksskeegfor");
    findLongestPalindromicString();
 
    strcpy(text, "caba");
    findLongestPalindromicString();
 
    strcpy(text, "abacdfgdcaba");
    findLongestPalindromicString();
 
    strcpy(text, "abacdfgdcabba");
    findLongestPalindromicString();
 
    strcpy(text, "abacdedcaba");
    findLongestPalindromicString();
 
    return 0;
}

Java

// A Java program to implement Manacher’s Algorithm
import java.lang.*;
 
class GFG{
     
public static void findLongestPalindromicString(
                   String text)
{
    int N = text.length();
    if(N == 0)
        return;
     
    // Position count
    N = 2 * N + 1;
     
    // LPS Length Array
    int []L = new int [N];
    L[0] = 0;
    L[1] = 1;
     
    // centerPosition
    int C = 1;
     
    // centerRightPosition
    int R = 2;
     
    // currentRightPosition
    int i = 0;
     
    // currentLeftPosition
    int iMirror;
    int expand = -1;
    int diff = -1;
    int maxLPSLength = 0;
    int maxLPSCenterPosition = 0;
    int start = -1;
    int end = -1;
     
    // Uncomment it to print LPS Length array
    // printf("%d %d ", L[0], L[1]);
    for (i = 2; i < N; i++)
    {
        // Get currentLeftPosition iMirror
        // for currentRightPosition i
        iMirror = 2 * C - i;
         
        // Reset expand - means no
        // expansion required
        expand = 0;
        diff = R - i;
         
        // If currentRightPosition i is
        // within centerRightPosition R
        if(diff >= 0)
        {
             
            // Case 1
            if(L[iMirror] < diff)
                L[i] = L[iMirror];
                 
            // Case 2
            else if(L[iMirror] == diff && R == N - 1)
                L[i] = L[iMirror];
             
            // Case 3
            else if(L[iMirror] == diff && R < N - 1)
            {
                    L[i] = L[iMirror];
                     
                     // Expansion required
                    expand = 1;
            }
             
            // Case 4
            else if(L[iMirror] > diff)
            {
                L[i] = diff;
                 
                // Expansion required
                expand = 1;
            }
        }
        else
        {
            L[i] = 0;
             
            // Expansion required
            expand = 1;
        }
         
        if (expand == 1)
        {
             
            // Attempt to expand palindrome centered
            // at currentRightPosition i. Here for odd
            // positions, we compare characters and
            // if match then increment LPS Length by ONE
            // If even position, we just increment LPS
            // by ONE without any character comparison
            try
            {
                while (((i + L[i]) < N &&
                        (i - L[i]) > 0) &&
                      (((i + L[i] + 1) % 2 == 0) ||
                       (text.charAt((i + L[i] + 1) / 2) ==
                        text.charAt((i - L[i] - 1) / 2))))
                {
                    L[i]++;
                }
            }
            catch (Exception e)
            {
                assert true;
            }
        }
         
        // Track maxLPSLength
        if(L[i] > maxLPSLength)
        {
            maxLPSLength = L[i];
            maxLPSCenterPosition = i;
        }
 
        // If palindrome centered at
        // currentRightPosition i expand
        // beyond centerRightPosition R,
        // adjust centerPosition C based
        // on expanded palindrome.
        if (i + L[i] > R)
        {
            C = i;
            R = i + L[i];
        }
         
        //Uncomment it to print LPS Length array
        //System.out.print("%d ", L[i]);
    }
     
    start = (maxLPSCenterPosition -
             maxLPSLength) / 2;
    end = start + maxLPSLength - 1;
     
    //System.out.print("start: %d end: %d\n",
    //                  start, end);
    System.out.print("LPS of string is " +
                      text + " : ");
     
    for(i = start; i <= end; i++)
        System.out.print(text.charAt(i));
    System.out.println();
}
 
// Driver code
public static void main(String []args)
{
    String text1="babcbabcbaccba";
    findLongestPalindromicString(text1);
 
    String text2="abaaba";
    findLongestPalindromicString(text2);
 
    String text3= "abababa";
    findLongestPalindromicString(text3);
 
    String text4="abcbabcbabcba";
    findLongestPalindromicString(text4);
 
    String text5="forgeeksskeegfor";
    findLongestPalindromicString(text5);
 
    String text6="caba";
    findLongestPalindromicString(text6);
 
    String text7="abacdfgdcaba";
    findLongestPalindromicString(text7);
 
    String text8="abacdfgdcabba";
    findLongestPalindromicString(text8);
 
    String text9="abacdedcaba";
    findLongestPalindromicString(text9);
}
}
 
// This code is contributed by SoumikMondal

Python3

# Python program to implement Manacher's Algorithm
  
def findLongestPalindromicString(text):
    N = len(text)
    if N == 0:
        return
    N = 2*N+1    # Position count
    L = [0] * N
    L[0] = 0
    L[1] = 1
    C = 1     # centerPosition
    R = 2     # centerRightPosition
    i = 0    # currentRightPosition
    iMirror = 0     # currentLeftPosition
    maxLPSLength = 0
    maxLPSCenterPosition = 0
    start = -1
    end = -1
    diff = -1
  
    # Uncomment it to print LPS Length array
    # printf("%d %d ", L[0], L[1]);
    for i in range(2,N):
      
        # get currentLeftPosition iMirror for currentRightPosition i
        iMirror = 2*C-i
        L[i] = 0
        diff = R - i
        # If currentRightPosition i is within centerRightPosition R
        if diff > 0:
            L[i] = min(L[iMirror], diff)
  
        # Attempt to expand palindrome centered at currentRightPosition i
        # Here for odd positions, we compare characters and
        # if match then increment LPS Length by ONE
        # If even position, we just increment LPS by ONE without
        # any character comparison
        try:
            while ((i+L[i]) < N and (i-L[i]) > 0) and \
                    (((i+L[i]+1) % 2 == 0) or \
                    (text[(i+L[i]+1)//2] == text[(i-L[i]-1)//2])):
                L[i]+=1
        except Exception as e:
            pass
  
        if L[i] > maxLPSLength:        # Track maxLPSLength
            maxLPSLength = L[i]
            maxLPSCenterPosition = i
  
        # If palindrome centered at currentRightPosition i
        # expand beyond centerRightPosition R,
        # adjust centerPosition C based on expanded palindrome.
        if i + L[i] > R:
            C = i
            R = i + L[i]
  
    # Uncomment it to print LPS Length array
    # printf("%d ", L[i]);
    start = (maxLPSCenterPosition - maxLPSLength) // 2
    end = start + maxLPSLength - 1
    print ("LPS of string is " + text + " : ",text[start:end+1])
  
# Driver program
text1 = "babcbabcbaccba"
findLongestPalindromicString(text1)
  
text2 = "abaaba"
findLongestPalindromicString(text2)
  
text3 = "abababa"
findLongestPalindromicString(text3)
  
text4 = "abcbabcbabcba"
findLongestPalindromicString(text4)
  
text5 = "forgeeksskeegfor"
findLongestPalindromicString(text5)
  
text6 = "caba"
findLongestPalindromicString(text6)
  
text7 = "abacdfgdcaba"
findLongestPalindromicString(text7)
  
text8 = "abacdfgdcabba"
findLongestPalindromicString(text8)
  
text9 = "abacdedcaba"
findLongestPalindromicString(text9)
  
# This code is contributed by BHAVYA JAIN

C#

// A C# program to implement Manacher’s Algorithm
using System;
using System.Diagnostics;
public class GFG
{
 
public static void findLongestPalindromicString(
                   String text)
{
    int N = text.Length;
    if(N == 0)
        return;
     
    // Position count
    N = 2 * N + 1;
     
    // LPS Length Array
    int []L = new int [N];
    L[0] = 0;
    L[1] = 1;
     
    // centerPosition
    int C = 1;
     
    // centerRightPosition
    int R = 2;
     
    // currentRightPosition
    int i = 0;
     
    // currentLeftPosition
    int iMirror;
    int expand = -1;
    int diff = -1;
    int maxLPSLength = 0;
    int maxLPSCenterPosition = 0;
    int start = -1;
    int end = -1;
     
    // Uncomment it to print LPS Length array
    // printf("%d %d ", L[0], L[1]);
    for (i = 2; i < N; i++)
    {
        // Get currentLeftPosition iMirror
        // for currentRightPosition i
        iMirror = 2 * C - i;
         
        // Reset expand - means no
        // expansion required
        expand = 0;
        diff = R - i;
         
        // If currentRightPosition i is
        // within centerRightPosition R
        if(diff >= 0)
        {
             
            // Case 1
            if(L[iMirror] < diff)
                L[i] = L[iMirror];
                 
            // Case 2
            else if(L[iMirror] == diff && R == N - 1)
                L[i] = L[iMirror];
             
            // Case 3
            else if(L[iMirror] == diff && R < N - 1)
            {
                    L[i] = L[iMirror];
                     
                     // Expansion required
                    expand = 1;
            }
             
            // Case 4
            else if(L[iMirror] > diff)
            {
                L[i] = diff;
                 
                // Expansion required
                expand = 1;
            }
        }
        else
        {
            L[i] = 0;
             
            // Expansion required
            expand = 1;
        }
         
        if (expand == 1)
        {
             
            // Attempt to expand palindrome centered
            // at currentRightPosition i. Here for odd
            // positions, we compare characters and
            // if match then increment LPS Length by ONE
            // If even position, we just increment LPS
            // by ONE without any character comparison
            try
            {
                while (((i + L[i]) < N &&
                        (i - L[i]) > 0) &&
                      (((i + L[i] + 1) % 2 == 0) ||
                       (text[(i + L[i] + 1) / 2] ==
                        text[(i - L[i] - 1) / 2])))
                {
                    L[i]++;
                }
            }
            catch (Exception)
            {
                Debug.Assert(true);
            }
        }
         
        // Track maxLPSLength
        if(L[i] > maxLPSLength)
        {
            maxLPSLength = L[i];
            maxLPSCenterPosition = i;
        }
 
        // If palindrome centered at
        // currentRightPosition i expand
        // beyond centerRightPosition R,
        // adjust centerPosition C based
        // on expanded palindrome.
        if (i + L[i] > R)
        {
            C = i;
            R = i + L[i];
        }
         
        //Uncomment it to print LPS Length array
        //System.out.print("%d ", L[i]);
    }
     
    start = (maxLPSCenterPosition -
             maxLPSLength) / 2;
    end = start + maxLPSLength - 1;
     
    //System.out.print("start: %d end: %d\n",
    //                  start, end);
    Console.Write("LPS of string is " +
                      text + " : ");
     
    for(i = start; i <= end; i++)
        Console.Write(text[i]);
    Console.WriteLine();
}
 
// Driver code
static public void Main ()
{
 
    String text1 = "babcbabcbaccba";
    findLongestPalindromicString(text1);
 
    String text2 = "abaaba";
    findLongestPalindromicString(text2);
 
    String text3 = "abababa";
    findLongestPalindromicString(text3);
 
    String text4 = "abcbabcbabcba";
    findLongestPalindromicString(text4);
 
    String text5 = "forgeeksskeegfor";
    findLongestPalindromicString(text5);
 
    String text6 = "caba";
    findLongestPalindromicString(text6);
 
    String text7 = "abacdfgdcaba";
    findLongestPalindromicString(text7);
 
    String text8 = "abacdfgdcabba";
    findLongestPalindromicString(text8);
 
    String text9 = "abacdedcaba";
    findLongestPalindromicString(text9);
}
}
 
// This code is contributed by Dharanendra L V.

Javascript

<script>
// A Javascript program to implement Manacher’s Algorithm
 
function findLongestPalindromicString(text)
{
    let N = text.length;
    if(N == 0)
        return;
      
    // Position count
    N = 2 * N + 1;
      
    // LPS Length Array
    let L = new Array(N);
    L[0] = 0;
    L[1] = 1;
      
    // centerPosition
    let C = 1;
      
    // centerRightPosition
    let R = 2;
      
    // currentRightPosition
    let i = 0;
      
    // currentLeftPosition
    let iMirror;
    let expand = -1;
    let diff = -1;
    let maxLPSLength = 0;
    let maxLPSCenterPosition = 0;
    let start = -1;
    let end = -1;
      
    // Uncomment it to print LPS Length array
    // printf("%d %d ", L[0], L[1]);
    for (i = 2; i < N; i++)
    {
        // Get currentLeftPosition iMirror
        // for currentRightPosition i
        iMirror = 2 * C - i;
          
        // Reset expand - means no
        // expansion required
        expand = 0;
        diff = R - i;
          
        // If currentRightPosition i is
        // within centerRightPosition R
        if(diff >= 0)
        {
              
            // Case 1
            if(L[iMirror] < diff)
                L[i] = L[iMirror];
                  
            // Case 2
            else if(L[iMirror] == diff && R == N - 1)
                L[i] = L[iMirror];
              
            // Case 3
            else if(L[iMirror] == diff && R < N - 1)
            {
                    L[i] = L[iMirror];
                      
                     // Expansion required
                    expand = 1;
            }
              
            // Case 4
            else if(L[iMirror] > diff)
            {
                L[i] = diff;
                  
                // Expansion required
                expand = 1;
            }
        }
        else
        {
            L[i] = 0;
              
            // Expansion required
            expand = 1;
        }
          
        if (expand == 1)
        {
              
            // Attempt to expand palindrome centered
            // at currentRightPosition i. Here for odd
            // positions, we compare characters and
            // if match then increment LPS Length by ONE
            // If even position, we just increment LPS
            // by ONE without any character comparison
             
             
                while (((i + L[i]) < N &&
                        (i - L[i]) > 0) &&
                      (((i + L[i] + 1) % 2 == 0) ||
                       (text[Math.floor((i + L[i] + 1) / 2)] ==
                        text[Math.floor((i - L[i] - 1) / 2)])))
                {
                    L[i]++;
                }
             
             
        }
          
        // Track maxLPSLength
        if(L[i] > maxLPSLength)
        {
            maxLPSLength = L[i];
            maxLPSCenterPosition = i;
        }
  
        // If palindrome centered at
        // currentRightPosition i expand
        // beyond centerRightPosition R,
        // adjust centerPosition C based
        // on expanded palindrome.
        if (i + L[i] > R)
        {
            C = i;
            R = i + L[i];
        }
          
        //Uncomment it to print LPS Length array
        //System.out.print("%d ", L[i]);
    }
      
    start = (maxLPSCenterPosition -
             maxLPSLength) / 2;
    end = start + maxLPSLength - 1;
      
    //System.out.print("start: %d end: %d\n",
    //                  start, end);
    document.write("LPS of string is " +
                      text + " : ");
      
    for(i = start; i <= end; i++)
        document.write(text[i]);
    document.write("<br>");
}
 
// Driver code
 
let text1="babcbabcbaccba";
findLongestPalindromicString(text1);
 
let text2="abaaba";
findLongestPalindromicString(text2);
 
let text3= "abababa";
findLongestPalindromicString(text3);
 
let text4="abcbabcbabcba";
findLongestPalindromicString(text4);
 
let text5="forgeeksskeegfor";
findLongestPalindromicString(text5);
 
let text6="caba";
findLongestPalindromicString(text6);
 
let text7="abacdfgdcaba";
findLongestPalindromicString(text7);
 
let text8="abacdfgdcabba";
findLongestPalindromicString(text8);
 
let text9="abacdedcaba";
findLongestPalindromicString(text9);
 
 
// This code is contributed by unknown2108
</script>
Producción

LPS of string is babcbabcbaccba : abcbabcba
LPS of string is abaaba : abaaba
LPS of string is abababa : abababa
LPS of string is abcbabcbabcba : abcbabcbabcba
LPS of string is forgeeksskeegfor : geeksskeeg
LPS of string is caba : aba
LPS of string is abacdfgdcaba : aba
LPS of string is abacdfgdcabba : abba
LPS of string is abacdedcaba : abacdedcaba

Complejidad temporal: O(N)
Espacio auxiliar: O(N)

Esta es la implementación basada en los cuatro casos discutidos en la Parte 2 . En la Parte 4 , hemos discutido una forma diferente de ver estos cuatro casos y algunos otros enfoques. 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *