3.8.9String Algorithms

Palindrome algorithms — Manacher's algorithm

2,308 words10 min readdifficulty · medium

WHAT problem are we solving?

WHY the # trick (transformation)

If t has length m=2n+1m = 2n+1, we compute an array ==P[i]====P[i]== = radius of the longest palindrome centered at t[i] (radius = number of characters on each side, in t).


HOW: the core recurrence (derive it)

We sweep ii left to right and maintain the rightmost-reaching palindrome found so far, described by its center CC and right boundary RR (so it covers [C(RC),R][C-(R-C),\, R], i.e. half-length RCR-C).

WHY the min\min — the two cases (Steel-man both)

That's why we take min(P[i],Ri)\min(P[i'],\, R-i): trust the mirror, but never trust beyond the wall.

Figure — Palindrome algorithms — Manacher's algorithm

Reference implementation

def manacher(s):
    t = '#' + '#'.join(s) + '#'        # length 2n+1
    m = len(t)
    P = [0]*m
    C = R = 0
    for i in range(m):
        if i < R:
            P[i] = min(P[2*C - i], R - i)   # mirror, capped at wall
        # expand
        while i - P[i] - 1 >= 0 and i + P[i] + 1 < m and \
              t[i - P[i] - 1] == t[i + P[i] + 1]:
            P[i] += 1
        # update rightmost
        if i + P[i] > R:
            C, R = i, i + P[i]
    return P   # P[i] = palindrome length in ORIGINAL s centered at t[i]
 
# longest palindromic substring:
def longest_pal(s):
    P = manacher(s)
    k = max(range(len(P)), key=lambda i: P[i])
    start = (k - P[k]) // 2          # map t-index back to s-index
    return s[start:start + P[k]]

Worked examples


Common mistakes


Recall Feynman: explain to a 12-year-old

Imagine a row of mirror tiles where the middle is a magic mirror. If you already know the left side perfectly reflects the right side, then to know what's at some spot, you can just peek at its mirror buddy instead of measuring again. You only do real measuring at the very edge where the mirror's reflection runs out. Because that edge only ever moves forward, you never re-measure the same ground twice — so the whole job is fast. The # symbols are just spacers we sprinkle in so that "even-length" mirrors and "odd-length" mirrors become the same shape and we only have to deal with one kind.


Flashcards

Why transform s into #a#b#...#?
It forces every palindrome in the new string to be odd-length, unifying odd/even cases (center is always one position).
What does P[i]P[i] store, and how does it relate to the original string?
Radius in transformed t; numerically equals the length of the corresponding palindrome in the original s.
What is the mirror index of ii about center CC?
i=2Cii' = 2C - i.
State the Manacher initialization for i<Ri < R.
P[i]=min(P[2Ci],  Ri)P[i] = \min(P[2C-i],\; R-i), then expand.
Why the min\min with RiR-i?
Symmetry only guarantees up to the right wall RR; beyond it we have no info, so we cap and expand manually.
In which case do you NOT expand?
When the mirror palindrome fits strictly inside the big one (P[i]<RiP[i'] < R-i): P[i]=P[i]P[i]=P[i'] exactly.
When do you update (C,R)(C,R)?
When i+P[i]>Ri + P[i] > R, set C=i, R=i+P[i]C=i,\ R=i+P[i].
Why is Manacher O(n)O(n)?
Mirror copy is O(1)O(1); expansion only moves RR forward, and RR rises monotonically from 00 to 2n+1\le 2n+1, so total expansion is O(n)O(n).
Map transformed center index kk back to start index in ss.
start = (k - P[k]) // 2.
How many palindromic substrings are centered at t[i]?
P[i]/2\lceil P[i]/2 \rceil.

Connections

  • Longest Palindromic Substring (DP O(n2)O(n^2) vs Manacher O(n)O(n))
  • Expand Around Center (the naive baseline Manacher accelerates)
  • Z-Algorithm & KMP failure function (other linear string preprocessing using reuse-of-prior-work)
  • Palindromic Tree (Eertree) (alternative for counting distinct palindromes)
  • Amortized Analysis (why the monotone RR argument gives linear time)

Concept Map

enables reuse of

reduced by reuse to

achieves

solved by

builds string t of length 2n+1

radius equals length in s

reflect i across C

gives initial value

then

if reaches past R

feeds

yields

Palindrome symmetry

Mirror copy

Naive O of n squared

O of n

Odd even headache

Insert separator #

Array P i = radius

Real palindrome length

Track center C and right bound R

Mirror index i' = 2C - i

P i = min of P i' and R - i

Expand while chars match

Update C and R

Longest palindrome and count

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Manacher ka core idea bahut simple hai: palindrome symmetric hota hai, yaani left side right side ka mirror hota hai. Toh agar tumne pehle ek bada palindrome already find kar liya hai, toh uske andar ki har cheez already mirror ho chuki hai. Naya center aata hai toh tum scratch se ginna shuru mat karo — apne mirror position ka answer copy kar lo, aur sirf utna hi expand karo jitna mirror guarantee nahi de raha. Isi reuse ki wajah se naive O(n2)O(n^2) ban jaata hai fast O(n)O(n).

Pehle ek trick: original string mein # daal do har character ke beech (abba#a#b#b#a#). Isse saare palindrome odd-length ban jaate hain, toh odd aur even ka alag-alag case handle karne ki tension khatam. Phir array P[i]P[i] banao = us center ka palindrome radius. Mazedaar baat: ye radius bilkul original string ke palindrome ki length ke barabar hota hai.

Main formula: agar current ii already-known bade palindrome ke andar hai (center CC, right wall RR), toh mirror nikaalo i=2Cii' = 2C - i aur P[i] = min(P[i'], R-i) set karo. min isliye, kyunki wall RR ke baad humein kuch pata nahi — symmetry ki guarantee wahin khatam ho jaati hai. Uske baad character-by-character expand karo, aur agar tum RR se aage nikal gaye toh (C,R)(C,R) update kar do.

Kyun fast? Mirror-copy O(1)O(1) hai, aur expand loop sirf tab kaam karta hai jab RR aage badhta hai — aur RR kabhi peeche nahi jaata, sirf 00 se 2n+12n+1 tak aage. Toh total expansion O(n)O(n). Exam/interview mein ye dhyaan rakho: min mein wall cap mat bhoolna, aur original index map karte time (k - P[k]) // 2 use karna — ye do hi sabse common galtiyaan hain.

Go deeper — visual, from zero

Test yourself — String Algorithms

Connections