16.12 Manacher Algorithm

You need to find palindromic substrings efficiently.

16.12 Manacher Algorithm

Problem

You need to find palindromic substrings efficiently.

Given:

forgeeksskeegfor

the longest palindromic substring is:

geeksskeeg

A brute-force solution checks every substring and tests whether it is a palindrome. There are O(n²) substrings, and each check may cost O(n), giving O(n³) time if implemented directly. Even a better expand-around-center approach still costs O(n²) in the worst case.

The challenge is to find all palindrome radii, and therefore the longest palindromic substring, in linear time.

Solution

Manacher's algorithm computes, for every center position, the radius of the longest palindrome centered there.

It reuses information from previously discovered palindromes. When a center lies inside a known palindrome, its mirror position gives a lower bound on the palindrome radius at the current center.

This is the same kind of idea seen in KMP, Z Algorithm, and suffix structures: do not repeat comparisons that previous work has already justified.

Odd and Even Palindromes

Palindromes have two possible centers.

Odd-length palindromes have a character at the center:

racecar
   ^

Even-length palindromes have a gap at the center:

abba
  ^

A direct implementation often computes two arrays:

odd[i]  = radius of longest odd palindrome centered at i
even[i] = radius of longest even palindrome centered between i-1 and i

For example:

ababa

Odd radii:

Index Center Longest odd palindrome Radius
0 a a 1
1 b aba 2
2 a ababa 3
3 b aba 2
4 a a 1

The largest radius is 3, producing length:

2 * 3 - 1 = 5

The Mirror Idea

Suppose we already know a palindrome:

a b a b a
0 1 2 3 4

centered at index 2, spanning from 0 to 4.

Now consider index 3. Its mirror around center 2 is index 1.

a b a b a
  ^   ^
  1   3

If the palindrome at index 1 has radius 2, then index 3 also inherits part of that radius, as long as it stays inside the known boundary.

Manacher's algorithm maintains the rightmost palindrome currently known. For each new center, it uses the mirror center to initialize the radius, then expands only if necessary.

Maintaining the Right Boundary

At each step the algorithm keeps:

l = left boundary of the current rightmost palindrome
r = right boundary of the current rightmost palindrome

For center i, if i lies inside [l, r], then:

mirror = l + r - i

The current radius can start from:

min(previous_radius_at_mirror, r - i + 1)

Only comparisons beyond r are new.

This is the linear-time argument. The right boundary only moves to the right, and every expansion advances it at most once.

Odd Palindrome Algorithm

The odd-palindrome version computes radii centered on characters.

def manacherOdd
  (s : Array Char)
  : Array Nat :=
by
  -- Maintain the current rightmost odd palindrome.
  -- Use mirror centers to initialize each radius.
  -- Expand when the known boundary is reached.
  sorry

Pseudocode:

odd = array of zeros
l = 0
r = -1

for i in 0 .. n-1:
    if i > r:
        k = 1
    else:
        mirror = l + r - i
        k = min(odd[mirror], r - i + 1)

    while i-k >= 0 and i+k < n and s[i-k] == s[i+k]:
        k += 1

    odd[i] = k

    if i + k - 1 > r:
        l = i - k + 1
        r = i + k - 1

The radius includes the center character. A radius of 1 means a single-character palindrome.

Even Palindrome Algorithm

The even-palindrome version computes radii centered between characters.

def manacherEven
  (s : Array Char)
  : Array Nat :=
by
  -- Maintain the current rightmost even palindrome.
  -- Use mirrored gap centers.
  sorry

Pseudocode:

even = array of zeros
l = 0
r = -1

for i in 0 .. n-1:
    if i > r:
        k = 0
    else:
        mirror = l + r - i + 1
        k = min(even[mirror], r - i + 1)

    while i-k-1 >= 0 and i+k < n and s[i-k-1] == s[i+k]:
        k += 1

    even[i] = k

    if i + k - 1 > r:
        l = i - k
        r = i + k - 1

A radius of 0 means no nonempty even palindrome at that center.

Example

For:

abba

Odd radii:

[1, 1, 1, 1]

Even radii:

[0, 0, 2, 0]

The even radius at index 2 corresponds to:

abba

centered between positions 1 and 2.

The length is:

2 * 2 = 4

Recovering the Longest Palindrome

After computing both arrays, scan them.

For odd radius k at center i:

length = 2k - 1
start  = i - k + 1

For even radius k at center i:

length = 2k
start  = i - k

Keep the maximum length.

For:

forgeeksskeegfor

the maximum comes from an even center and yields:

geeksskeeg

Why It Is Linear

The expansion loops look suspicious because they are nested inside a loop over centers.

The key point is that expansions only compare characters beyond the current known right boundary. Each successful expansion moves that boundary to the right. Since the boundary cannot move past the end of the string, the total number of successful expansions is O(n).

The failed comparisons also occur once per center.

Therefore the total runtime is:

O(n)

Complexity Analysis

Let n be the length of the string.

Operation Complexity
Odd radii O(n)
Even radii O(n)
Longest palindrome recovery O(n)
Total O(n)
Storage O(n)

Manacher vs Eertree

Feature Manacher Eertree
Finds longest palindromic substring Yes Yes
Computes palindrome radius at every center Yes Indirect
Stores distinct palindromes No Yes
Counts distinct palindromes No Yes
Occurrence counting Limited Natural
Construction O(n) O(n)
Implementation difficulty Moderate Higher

Use Manacher when you need palindrome lengths or the longest palindrome.

Use an Eertree when you need the set of distinct palindromes or occurrence statistics.

Correctness

For each center, the algorithm initializes the radius using the mirror center when possible. The copied radius is valid because both centers lie inside a larger palindrome, so their internal characters correspond symmetrically.

If the copied radius reaches the current right boundary, the algorithm expands explicitly and verifies each additional character pair.

Thus each stored radius is neither too small nor too large. It contains all characters that can be justified by symmetry plus every additional matching pair found by direct comparison. The result is the exact maximum palindrome radius for every center.

Common Pitfalls

Do not mix the odd and even definitions. Odd radii include the center character; even radii count pairs around a gap.

Be careful with boundary arithmetic. Most bugs in Manacher's algorithm are off-by-one errors.

Do not use byte indexing blindly for Unicode text. A palindrome over bytes may differ from a palindrome over code points or grapheme clusters.

Remember that Manacher gives radii, not a list of distinct palindromes. Many radii may describe overlapping occurrences of the same palindrome.

Takeaway

Manacher's algorithm is the standard linear-time method for palindrome radii. It works by carrying forward symmetry information from the rightmost known palindrome and expanding only when new information is required. For longest-palindrome and all-center palindrome-radius problems, it is simpler and lighter than a palindromic tree while retaining optimal linear performance.