📜  Manacher算法-线性时间最长回文子串-第3部分

📅  最后修改于: 2021-04-29 09:47:44             🧑  作者: Mango

在Manacher的算法第1部分和第2部分中,我们介绍了一些基础知识,了解LPS长度数组以及如何基于四种情况有效地计算长度数组。在这里,我们将实现相同的功能。
我们已经看到,在情况1和情况2中不需要新的字符比较。在情况3和情况4中,需要进行新的比较。
在下图中,

Manacher算法-线性时间最长回文子串

如果根本需要比较,我们将只比较实际字符,它们位于“奇数”位置,例如1、3、5、7等。
即使位置不字符串代表一个字符,所以没有比较,将在预制甚至位置。
如果在不同奇数位置的两个字符匹配,则它们将使LPS长度增加2。
根据处理偶数和奇数位置的方式,有许多种实现方法。一种方法是创建一个新的字符串1,我们插入的所有位置,甚至一些独特的字符(比如#,$等),然后运行算法上(避免的偶数和奇数位置的处理方式不同)。其他方法可能是处理给定的字符串本身,但此处应适当处理偶数和奇数位置。
在这里,我们将从给定的字符串本身开始。当需要扩展和字符比较时,我们将在左右位置逐一扩展。当找到奇数位置时,将进行比较,并且LPS长度将增加1。当找到偶数位置时,不进行比较,并且LPS长度将增加1(因此,总体而言,左侧和右侧的一个奇数和一个偶数位置将使LPS长度增加2)。

C
// A C program to implement Manacher’s Algorithm
#include 
#include 
 
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


Python
# 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 xrange(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 + " : ",
    print text[start:end+1],
    print "\n",
  
# 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.


输出:

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