Problem Statement
Manacher's Algorithm
A palindrome is a string that reads the same forwards and backwards, like "aba" or "noon". Our job is to find the longest palindrome hiding inside a string. The slow way is to stand at every letter and grow outward, checking left and right, until the two sides stop matching. That works, but it redoes a lot of comparisons. Manacher's algorithm is the fast way: it does the same growing idea, but it remembers the palindromes it already found and reuses that memory to skip work it has already done. The result is O(n) time, meaning the work grows in a straight line with the length of the string, instead of O(n squared), which grows much faster.
Signals to notice
Brute force first
Expand around each center — O(n²).
The key insight
Manacher's: use known palindrome radii to skip redundant expansion. Maintain rightmost boundary and center. O(n).
Trace it on s="cbbd" → t="#c#b#b#d#" (n=9)
i=1 ('c'): 1<right(0) false; expand p[1]=1 (t[2]='#'==t[0]='#'); 1+1>0 → center=1,right=2
i=3 ('b'): 3<right(2) false; expand p[3]=1 (t[4]='#'==t[2]='#'); 3+1>2 → center=3,right=4
i=4 ('#'): 4<right(4) false; expand p[4]=2 (t[5]='b'==t[3]='b', t[6]='#'==t[2]='#'); 4+2>4 → center=4,right=6
i=5 ('b'): 5<right(6) true, mirror=3 → p[5]=min(6-5,p[3]=1)=1; expand fails (t[7]='d'≠t[3]='b'); 5+1>6 false → center,right unchanged
i=7 ('d'): 7<right(6) false; expand p[7]=1 (t[8]='#'==t[6]='#'); 7+1>6 → center=7,right=8
skipped i=0,2,6,8 all give p=0; final p=[0,1,0,1,2,1,0,1,0]
max_len=2 at ci=4; start=(4-2)//2=1 → s[1:3]="bb"What must stay true
If position i is within a known palindrome, the mirror's radius provides a starting point. Only expand beyond the known boundary.
Shape of the loop
t = "#" + interleave(s) + "#"; n = len(t); p[0..n) = 0; center = right = 0
for i in 0..n:
if i < right: p[i] = min(right - i, p[2*center - i]) # reuse mirror radius
while i+p[i]+1 < n and i-p[i]-1 >= 0 and t[i+p[i]+1] == t[i-p[i]-1]:
p[i] += 1 # expand beyond known boundary
if i + p[i] > right: center, right = i, i + p[i] # extend rightmost palindrome
maxLen = max(p); ci = index_of(maxLen); start = (ci - maxLen) // 2
return s[start : start + maxLen]Pseudocode only — the full worked solution lives in the Solution tab.
Easy way to go wrong
Not handling boundary cases when the mirror's palindrome extends beyond the rightmost boundary.