Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Find the longest substring that reads the same forwards and backwards. Expand-around-center is O(n²) and is the answer most candidates should reach. Manacher's algorithm gets it to O(n): transform the string by inserting separators so every palindrome is odd-length, then sweep left to right maintaining the rightmost palindrome [center, right]. Inside that boundary you seed each radius from its mirror before expanding, so each character is examined O(1) amortized times.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you can first give the clean O(n²) expand-around-center, then explain why naive checking is wasteful and how mirror symmetry inside a known palindrome removes the redundancy.
Where candidates slip
Botching the index mapping between the transformed and original strings, or forgetting the min(right − i, mirror) cap so symmetry is assumed past the verified boundary.
How to stand out
Lead with expand-around-center (the realistic interview answer), then derive Manacher's mirror trick and the right-never-moves-back invariant, and convert p[i] back to original coordinates correctly.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachExplore the full treeCollapse the tree
How to read it:Most interviews want the middle rung; Manacher is the O(n) summit for hard constraints.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Expand Around Center
1Hint 1Explore hintHide hint
A palindrome is defined by its center. How many centers are there? n single-character centers (odd length) plus n−1 gaps between characters (even length) → 2n−1 centers.
2Hint 2Explore hintHide hint
From each center, expand two pointers outward while the characters match and stay in bounds. The widest expansion over all centers is the answer.
3Hint 3Explore hintHide hint
Track the best (start, length) seen. Each expansion is O(n) and there are O(n) centers → O(n²).
A · Core idea
Expand-around-center grows palindromes outward from every possible middle.
Centers, not substrings. Every palindrome has a center: a single character for odd lengths, or the gap between two characters for even lengths. There are n odd centers and n−1 even centers, 2n−1 in total — far fewer than the n² substrings the brute force checks.
The expansion. From a center, set a left pointer and a right pointer and move them outward while s[left] == s[right] and both stay in bounds. When they stop, s[left+1..right−1] is the maximal palindrome at that center. Compare its length to the best so far.
Handling both parities. Run the expansion twice per index i: once with left = right = i (odd-length palindrome centered on a character), once with left = i, right = i+1 (even-length palindrome centered in the gap). Take the longer.
Why it's the right default. It's short, hard to get wrong, and O(n²) clears typical constraints (n ≤ a few thousand) comfortably. State it first; only escalate to Manacher when the interviewer pins the input size at something that needs linear time.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "babad"Array state
center 1
l=r=1 ('a')
"bab"C · Code with teaching comments
Reference implementation previewpublic class ExpandCenter { public String longestPalindrome(String s) { if (s.isEmpty()) return ""; int start = 0, end = 0; for (int i = 0; i < s.length(); i++) {Explore the full codeHide the full code
D · Why it works and complexityO(n²) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The leap from O(n³) to O(n²) is realizing you don't enumerate substrings — you enumerate the 2n−1 centers and let each palindrome reveal its own length by expanding. Manacher's further leap is noticing that neighboring centers' expansions overlap, so many comparisons are redundant.
ComplexityO(n²) time, O(1) space — There are 2n−1 centers; each expansion can grow up to n/2 steps → O(n²) total. Only a few indices of bookkeeping → O(1) extra space.
E · Edge cases and pitfalls3Handling only odd centers and missing even-length palindromes like "bb".Explore edge casesHide edge cases
Pitfalls
- Handling only odd centers and missing even-length palindromes like "bb".
- Wrong start/end recovery from the returned length — off-by-one on (len−1)/2.
- Re-deriving substrings instead of expanding from centers (back to O(n³)).
Approach 2 of 2 · Optimal
Manacher's Algorithm (Optimal)
1Hint 1Explore hintHide hint
Even and odd palindromes are annoying because they have different center types. Insert a separator like '#' between every character and at both ends: "abba" → "#a#b#b#a#". Now every palindrome is odd-length and centered on a real position.
2Hint 2Explore hintHide hint
Define p[i] as the radius of the palindrome centered at transformed index i. Maintain the rightmost palindrome you've seen as [center, right].
3Hint 3Explore hintHide hint
If i is inside [center, right], its mirror j = 2*center − i already has a known radius. Seed p[i] = min(right − i, p[j]) — capped because beyond 'right' you haven't checked symmetry — then expand explicitly. If you pass 'right', move the window.
A · Core idea
Manacher's algorithm computes, in linear time, the palindrome radius at every center by reusing symmetry the way the Z-algorithm reuses prefix matches.
Step 1 — the transform removes the parity split. Build t by inserting a separator # between every pair of characters and at both ends: "abba" becomes "#a#b#b#a#". This has two effects. First, t always has odd length 2n+1, so every palindrome in t is odd-length and centered on a single index — the even/odd case distinction disappears. Second, because of the padding, the radius p[i] of the palindrome centered at t[i] equals the length of the corresponding palindrome in the original string. That coincidence is what makes the bookkeeping clean.
Step 2 — the rightmost-palindrome window. Sweep i left to right over t, maintaining center and right, the center and right edge of the palindrome discovered so far that reaches farthest right (right = center + p[center]).
Step 3 — borrow from the mirror. When processing i, if i < right, then i lies inside the current palindrome, which is symmetric about center. Its mirror index is j = 2*center − i. By symmetry, the palindrome at i is at least as wide as the one at j — up to the boundary. So seed p[i] = min(right − i, p[j]). The min is essential: beyond right the characters were never compared, so you can't assume the mirror's full radius carries over. If i >= right, start with p[i] = 0.
Step 4 — expand and slide. After seeding, try to extend: while t[i + p[i] + 1] == t[i − p[i] − 1], increment p[i]. These comparisons happen only past the current right. If the new palindrome reaches beyond right, update center = i, right = i + p[i].
Why it's linear. Every successful character comparison advances right, and right moves only forward across 2n+1 positions. So across the entire sweep there are at most O(n) successful comparisons, plus one failing comparison per index. The mirror seeding is constant time. That's the whole O(n) argument — identical in spirit to the Z-algorithm's monotone r.
Step 5 — map back. The answer length is max(p[i]). The starting index in the original string for that center is (i − p[i]) / 2, because each original character sits at an odd transformed index and the # padding doubles positions. Slice the original string from there for p[i] characters.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
s = "abba" → t = "#a#b#b#a#"Array state
i=5
inside window; mirror = 2·4−5 = 3
"abba"C · Code with teaching comments
D · Why it works and complexityO(n) timeO(n) spaceOpen the invariant and proofExplore the proofHide the proof
Manacher is Z-thinking for palindromes. The #-transform turns 'two kinds of palindrome' into 'one kind', and the rightmost-palindrome window lets each new center inherit its mirror's radius for free, paying real comparisons only when it extends past everything seen — which, because the boundary only moves forward, totals linear work. Use it only when O(n) is mandatory; otherwise expand-around-center is the saner choice.
ComplexityO(n) time, O(n) space — Each explicit expansion step increases 'right', and 'right' only ever moves forward across the 2n+1 transformed positions. So the total expansion work is O(n). The mirror seeding is O(1) per index. Building the transformed string and mapping back are O(n). Total O(n) time, O(n) space for the transform and the p array.
E · Edge cases and pitfalls7s = "cbbd" — Transform puts a '#' center between the b's; the algorithm finds even-length "bb".Explore edge casesHide edge cases
Edge cases handled
s = "cbbd"Transform puts a '#' center between the b's; the algorithm finds even-length "bb".s = "aaaa"Nested palindromes; mirror reuse seeds most radii, expansion stays O(n) overall.s = "a"t = "#a#"; p = [0,1,0]; best length 1 → "a".
Pitfalls
- Omitting the min(right − i, p[mirror]) cap — assumes symmetry past the verified boundary.
- Wrong mapping back: original start is (center − radius) / 2; off-by-one corrupts the answer.
- Letting 'right' move backward — breaks the linear-time guarantee.
- Reaching for Manacher when O(n²) was fine — extra complexity, more chances to introduce bugs.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic class Manacher { public String longestPalindrome(String s) { if (s.isEmpty()) return ""; StringBuilder sb = new StringBuilder("#"); for (char c : s.toCharArray()) { sb.append(c).append('#'); }Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Missing the boundary cap on the mirror
Beyond 'right' the characters were never compared. Copying the full mirror radius assumes symmetry you haven't verified and over-reports the palindrome length.
Explore the code comparisonHide the code comparison
Missing the boundary cap on the mirror
Beyond 'right' the characters were never compared. Copying the full mirror radius assumes symmetry you haven't verified and over-reports the palindrome length.
Don't write this
if i < right:
p[i] = p[2 * center - i] # ignores the boundaryWrite this instead
if i < right:
p[i] = min(right - i, p[2 * center - i])2Wrong index mapping back to the original
Each original character sits at an odd transformed index. The start in the original string is (center − radius) // 2; using center − radius (without /2) slices the wrong substring.
Explore the code comparisonHide the code comparison
Wrong index mapping back to the original
Each original character sits at an odd transformed index. The start in the original string is (center − radius) // 2; using center − radius (without /2) slices the wrong substring.
Don't write this
start = best_center - best_len # transformed coordinates, wrongWrite this instead
start = (best_center - best_len) // 23Using Manacher where expand-around-center suffices
Manacher is intricate and easy to get subtly wrong under interview pressure. If O(n²) clears the constraints, the simpler center expansion is the safer, more communicable answer.
Explore the code comparisonHide the code comparison
Using Manacher where expand-around-center suffices
Manacher is intricate and easy to get subtly wrong under interview pressure. If O(n²) clears the constraints, the simpler center expansion is the safer, more communicable answer.
Don't write this
# n <= 1000 but candidate writes full Manacher with index bugsWrite this instead
# n <= 1000: expand-around-center, O(n^2), simple and correctRevise
Carry the pattern into the interview
Pattern to remember
Mirror reuse inside the rightmost palindrome boundary (like Z, for palindromes)
Code pattern to memorize
transform: "#a#b#a#" (n -> 2n+1, all palindromes odd)
p[i] = radius of palindrome centered at transformed index i
if i < right: p[i] = min(right - i, p[mirror]) mirror = 2*center - i
expand while chars match; if i + p[i] > right: center = i, right = i + p[i]
answer length = max(p[i]); original start = (i - p[i]) / 2Rules to remember
- 1Insert separators (
#) between and around every character so even- and odd-length palindromes both become odd in the transformed string — one case to handle, not two. - 2
p[i]in the transformed string equals the palindrome length in the original string (a neat consequence of the#padding). - 3Inside the current
[center, right], seedp[i]from its mirror2*center − i, capped at `right − i` — pastrightyou haven't verified symmetry. - 4Only the explicit expansion can push
rightrightward, andrightnever retreats — that monotonicity is the O(n) proof, exactly as in the Z-algorithm. - 5Map back carefully: original start index is
(i − p[i]) / 2. Off-by-one here is the most common Manacher bug.
Use this pattern when
- Longest palindromic substring with a strict O(n) requirement
- Counting all palindromic substrings in linear time
- Queries about palindrome radii at every center
- When expand-around-center's O(n²) is too slow for the input size
Choose another pattern when
- n is small or O(n²) is acceptable → expand-around-center is far simpler and less bug-prone
- You need longest palindromic *subsequence* (non-contiguous) → that's DP, not Manacher
- Only checking if the whole string is a palindrome → two pointers, O(n), no transform
- Counting distinct palindromes → palindromic tree (Eertree), a different structure
Interview takeaway
Manacher is the Z-algorithm idea applied to palindromes: the `#`-transform removes the odd/even split, and a rightmost-palindrome window lets each new center borrow its mirror's radius before expanding. Reach for it only when O(n) is genuinely required.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternMirror-reuse within a rightmost boundary — the same engine as the Z-algorithm, specialized to palindromes via the #-transform. Recognise it for linear-time palindrome radius/length queries; otherwise expand-around-center is the pragmatic default.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Count All Palindromic SubstringsComing soonSum (p[i] + 1) // 2 over Manacher's radii, or count expansions in the center method.
- Longest Palindromic SubsequenceComing soonDifferent problem — non-contiguous — solved with interval DP, not Manacher.
- Shortest Palindrome (prepend characters)Coming soonUse KMP on s + '#' + reverse(s) to find the longest palindromic prefix.
- Palindrome Partitioning (min cuts)Coming soonPrecompute palindrome boundaries (Manacher or DP) then DP over cut positions.
Same pattern