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
DSA Tutorial - Learn Data Structures and Algorithms DSA (Data Structures and Algorithms) is the study of organizing data efficiently using data structures like arrays, stacks, and trees, paired with step-by-step procedures (or algorithms) to solve problems effectively. Data structures manage how data is stored and accessed, while algorithms focus on
7 min read
Quick Sort QuickSort is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array. It works on the principle of divide and conquer, breaking down the problem into s
12 min read
Merge Sort - Data Structure and Algorithms Tutorials Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer approach. It works by recursively dividing the input array into two halves, recursively sorting the two halves and finally merging them back together to obtain the sorted array. Merge
14 min read
Bubble Sort Algorithm Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case time complexity are quite high.We sort the array using multiple passes. After the fir
8 min read
Data Structures Tutorial Data structures are the fundamental building blocks of computer programming. They define how data is organized, stored, and manipulated within a program. Understanding data structures is very important for developing efficient and effective algorithms. What is Data Structure?A data structure is a st
2 min read
Breadth First Search or BFS for a Graph Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
15+ min read
Binary Search Algorithm - Iterative and Recursive Implementation Binary Search Algorithm is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N). Binary Search AlgorithmConditions to apply Binary Searc
15 min read
Insertion Sort Algorithm Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list. It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards. T
9 min read
Dijkstra's Algorithm to find Shortest Paths from a Source to all Given a weighted undirected graph represented as an edge list and a source vertex src, find the shortest path distances from the source vertex to all other vertices in the graph. The graph contains V vertices, numbered from 0 to V - 1.Note: The given graph does not contain any negative edge. Example
12 min read
Selection Sort Selection Sort is a comparison-based sorting algorithm. It sorts an array by repeatedly selecting the smallest (or largest) element from the unsorted portion and swapping it with the first unsorted element. This process continues until the entire array is sorted.First we find the smallest element an
8 min read