Manacher's Algorithm - Linear Time Longest Palindromic Substring - Part 3
Last Updated : 24 Mar, 2023
In Manacher's Algorithm Part 1 and Part 2, we gone through some of the basics, understood LPS length array and how to calculate it efficiently based on four cases. Here we will implement the same.
We have seen that there are no new character comparison needed in case 1 and case 2. In case 3 and case 4, necessary new comparison are needed.
In following figure,

If at all we need a comparison, we will only compare actual characters, which are at "odd" positions like 1, 3, 5, 7, etc.
Even positions do not represent a character in string, so no comparison will be performed for even positions.
If two characters at different odd positions match, then they will increase LPS length by 2.
There are many ways to implement this depending on how even and odd positions are handled. One way would be to create a new string 1st where we insert some unique character (say #, $ etc) in all even positions and then run algorithm on that (to avoid different way of even and odd position handling). Other way could be to work on given string itself but here even and odd positions should be handled appropriately.
Here we will start with given string itself. When there is a need of expansion and character comparison required, we will expand in left and right positions one by one. When odd position is found, comparison will be done and LPS Length will be incremented by ONE. When even position is found, no comparison done and LPS Length will be incremented by ONE (So overall, one odd and one even positions on both left and right side will increase LPS Length by TWO).
Implementation:
C++ // A C++ program to implement Manacher’s Algorithm #include <bits/stdc++.h> using namespace std; void findLongestPalindromicString(string text) { int N = text.length(); if (N == 0) return; // Position count N = 2 * N + 1; // LPS Length Array int L[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 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]++; } } // 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); cout << "LPS of string is " << text << " : "; for (i = start; i <= end; i++) cout << text[i]; cout << endl; } int 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); return 0; } // This code is contributed by Ishankhandelwals.
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; } // This code is contributed by Ishan Khandelwal
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 let flr1 = Math.floor((i + L[i] + 1) / 2)); let flr2 = Math.floor((i + L[i] - 1) / 2)); while (((i + L[i]) < N && (i - L[i]) > 0) && (((i + L[i] + 1) % 2 == 0) || (text[flr] == text[flr]))) { 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>
OutputLPS 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
Time Complexity: O(N)
Auxiliary Space: O(N)
This is the implementation based on the four cases discussed in Part 2. In Part 4, we have discussed a different way to look at these four cases and few other approaches.
Similar Reads
Manacher's Algorithm - Linear Time Longest Palindromic Substring - Part 4 In Manacher's Algorithm Part 1 and Part 2, we gone through some of the basics, understood LPS length array and how to calculate it efficiently based on four cases. In Part 3, we implemented the same. Here we will review the four cases again and try to see it differently and implement the same. All f
12 min read
Manacher's Algorithm - Linear Time Longest Palindromic Substring - Part 2 In Manacher's Algorithm - Part 1 , we gone through some of the basics and LPS length array. Here we will see how to calculate LPS length array efficiently. To calculate LPS array efficiently, we need to understand how LPS length for any position may relate to LPS length value of any previous already
11 min read
Suffix Tree Application 6 - Longest Palindromic Substring Given a string, find the longest substring which is palindrome.We have already discussed Naïve [O(n3)], quadratic [O(n2)] and linear [O(n)] approaches in Set 1, Set 2 and Manacherâs Algorithm. In this article, we will discuss another linear time approach based on suffix tree. If given string is S, t
15+ min read
Longest Palindromic Substring using hashing in O(nlogn) Given a string S, The task is to find the longest substring which is a palindrome using hashing in O(N log N) time. Input: S: âforgeeksskeegforâ, Output: âgeeksskeegâ Input: S: âGeeksâ, Output: âeeâ Hashing to Solve the Problem:The hashing approach to solving the longest palindromic substring proble
11 min read
Print the longest palindromic prefix of a given string Given a string str, the task is to find the longest palindromic prefix of the given string. Examples: Input: str = "abaac" Output: aba Explanation: The longest prefix of the given string which is palindromic is "aba". Input: str = "abacabaxyz" Output: abacaba Explanation: The prefixes of the given s
12 min read