Longest Palindromic Substring – Solution & Complexity

1. Choose an Approach

  • Checking every substring for being a palindrome is O(n^3).
  • The clean, interview-friendly optimum is to expand around every possible center in O(n^2) time and O(1) space.
  • A palindrome is fully described by its center, so we grow outward from each center and remember the longest match.

2. Expand Around a Center

  • From a center, move two pointers outward while the characters match and stay in bounds.
  • Return the start and end indices of the widest palindrome found for that center.
def expand(s, left, right):
    while left >= 0 and right < len(s) and s[left] == s[right]:
        left -= 1
        right += 1
    # step back to the last matching pair
    return left + 1, right - 1

3. Track the Longest Over All Centers

  • There are 2n - 1 centers: one at each character (odd length) and one between each pair (even length).
  • For each center, expand and update the best (start, end) window whenever a longer palindrome is found.
def longest_palindrome(s: str) -> str:
    if not s:
        return ""
    start, end = 0, 0
    for i in range(len(s)):
        for l, r in (expand(s, i, i), expand(s, i, i + 1)):
            if r - l > end - start:
                start, end = l, r
    return s[start:end + 1]

4. Final Complete Solution

  • Each of the 2n - 1 centers expands at most O(n) times, so the total time is O(n^2).
  • We only store a couple of indices, so the extra space is O(1).
def longest_palindrome(s: str) -> str:
    if not s:
        return ""

    def expand(left: int, right: int) -> tuple[int, int]:
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return left + 1, right - 1

    start, end = 0, 0
    for i in range(len(s)):
        for l, r in (expand(i, i), expand(i, i + 1)):
            if r - l > end - start:
                start, end = l, r
    return s[start:end + 1]

FAQ

See also: