LeetCode #5 — Medium

Longest Palindromic
Substring

A complete visual walkthrough of the expand-around-center approach — from brute force to elegant O(n²) solution.

Patterns Used

Roadmap

  1. Brute Force — Check Every Substring
  2. The Core Insight — Expand Around Center
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Demo
  7. Complexity Analysis
Step 01

Brute Force — Check Every Substring

The naive approach: enumerate every possible substring, check if it is a palindrome, and track the longest one found.

Checking substrings of "babad"

For a string of length n, there are n(n+1)/2 substrings. Each palindrome check takes O(n) time, giving O(n³) total.

len=5
b
a
b
a
d
not palindrome
len=4
b
a
b
a
d
not palindrome
len=3
b
a
b
a
d
palindrome! "bab"

We must check every substring at every starting position — even after finding "bab", we continue checking the rest. This is wasteful.

šŸ’”

O(n³) is too slow. For n = 1000, that is up to 1 billion operations. We need an approach that avoids redundant checking. What if we could grow palindromes outward from their centers instead?

Step 02

The Core Insight — Expand Around Center

Every palindrome has a center. For odd-length palindromes, the center is a single character. For even-length palindromes, the center is the gap between two characters.

Two Types of Centers

ODD LENGTH
r
a
c
a
r
Center = single char "c"
expand(s, i, i)
EVEN LENGTH
a
b
b
a
Center = two chars "bb"
expand(s, i, i+1)

For a string of length n, there are 2n - 1 possible centers (n single-character centers + n-1 between-character centers). From each center, we expand outward while characters match.

⚔

The key advantage: expansion stops the moment characters do not match. We never check substrings that cannot possibly be palindromes. Each expansion takes at most O(n), and there are O(n) centers, giving us O(n²) total — a huge improvement over brute force.

Step 03

Algorithm Walkthrough

Let's trace through "babad" step by step, expanding from each center.

Center i = 0: "b" (odd expansion)

b
a
b
a
d

Cannot expand left (at boundary). Palindrome: "b" (length 1)

Center i = 1: "a" (odd expansion)

b
a
b
a
d
← expand →

s[0]='b' == s[2]='b'? Yes! Expand further: s[-1] is out of bounds. Stop.

Palindrome: "bab" (length 3) — new best!

Center i = 2: "b" (odd expansion)

b
a
b
a
d
← expand →

s[1]='a' == s[3]='a'? Yes! Expand: s[0]='b' == s[4]='d'? No! Stop.

Palindrome: "aba" (length 3) — ties the best.

Even-length check: centers (0,1), (1,2), (2,3), (3,4)

(0,1) s[0]='b' != s[1]='a' len=0
(1,2) s[1]='a' != s[2]='b' len=0
(2,3) s[2]='b' != s[3]='a' len=0
(3,4) s[3]='a' != s[4]='d' len=0

No adjacent duplicates in "babad", so no even-length palindromes longer than 0.

šŸŽÆ

Result: "bab" (or "aba") — both are length 3 palindromes found by expanding from centers at index 1 and 2 respectively. The algorithm returns whichever it finds first.

Even-length example: "cbbd"

c
b
b
d
← expand from center (1,2) →

s[1]='b' == s[2]='b'? Yes! Expand: s[0]='c' == s[3]='d'? No! Stop. Palindrome: "bb" (length 2)

Step 04

Edge Cases

The expand-around-center approach handles all edge cases naturally, without special-case code.

Cases to Consider

  • "a" → "a" Single character is always a palindrome.
  • "aaaa" → "aaaa" All same characters. Expansion from center i=1 (even) or i=2 (odd) covers the full string.
  • "racecar" → "racecar" Entire string is a palindrome. Expanding from center i=3 finds it.
  • "abcde" → "a" No palindrome longer than 1. Every character is its own palindrome.
  • "" → "" Empty or null string. The guard clause handles this immediately.
šŸ’”

No special-case code needed. The loop naturally handles single characters (expansion returns 1), all-same characters (expansion reaches boundaries), and no-palindrome cases (each center yields length 1). The only guard is for null/empty input.

Step 05

Full Annotated Code

class Solution {
    public String longestPalindrome(String s) {

        // Guard: handle null or empty input
        if (s == null || s.length() < 1) return "";

        int start = 0, maxLen = 0;

        // Try every possible center
        for (int i = 0; i < s.length(); i++) {

            // Odd-length palindrome: single char center
            int len1 = expand(s, i, i);

            // Even-length palindrome: two char center
            int len2 = expand(s, i, i + 1);

            // Take the longer of the two expansions
            int len = Math.max(len1, len2);

            // Update best if this palindrome is longer
            if (len > maxLen) {
                maxLen = len;
                // Calculate the starting index of this palindrome
                start = i - (len - 1) / 2;
            }
        }

        return s.substring(start, start + maxLen);
    }

    // Expand outward from center while chars match
    private int expand(String s, int left, int right) {

        // Keep expanding while in bounds and chars match
        while (left >= 0
            && right < s.length()
            && s.charAt(left) == s.charAt(right)) {
            left--;    // move left pointer outward
            right++;   // move right pointer outward
        }

        // Length of palindrome found
        // (left and right have moved one step past the palindrome)
        return right - left - 1;
    }
}
⚔

Why right - left - 1? When the while loop exits, left and right have each moved one step beyond the palindrome boundaries. So the actual palindrome spans from left+1 to right-1, giving length (right-1) - (left+1) + 1 = right - left - 1.

šŸ“

Why start = i - (len - 1) / 2? The center is at index i. For a palindrome of length len, the left edge is (len-1)/2 positions before the center. Integer division handles both odd and even lengths correctly.

Step 06

Interactive Demo

Enter a string and step through the expand-around-center algorithm. Watch both odd and even expansions at each center.

āš™ Expand-Around-Center Visualizer


Step 07

Complexity Analysis

Time
O(n²)
Space
O(1)

We iterate through 2n - 1 centers, and each expansion can take up to O(n) in the worst case (e.g., "aaaa...a"). No extra arrays or matrices are needed — just a few integer variables to track the best palindrome.

Approach Comparison

BRUTE FORCE
O(n³)
Check all substrings
EXPAND CENTER
O(n²)
This solution
MANACHER'S
O(n)
Advanced technique
šŸ“

Why not Manacher's? Manacher's algorithm achieves O(n) by reusing previously computed palindrome information. However, the expand-around-center approach is far simpler, uses O(1) space, and is the expected solution for interviews. O(n²) comfortably handles the constraint of n ≤ 1000.