49. Longest Palindromic Fragment
Problem
A lighter, more abstract warm-up: given a normalized (lowercased, whitespace-stripped) query string, find the longest contiguous fragment that reads the same forwards and backwards. This is a pure string-DP / two-pointer practice problem, loosely framed as a Fin string-processing exercise rather than tied to any specific Fin behavior.
If multiple fragments tie for the longest length, return the earliest-starting one. An empty input string returns an empty string.
Source: src/49_longest_palindromic_query_fragment.py
def longest_palindrome(s: str) -> str:
>>> longest_palindrome(s="babad")
'bab'
>>> longest_palindrome(s="cbbd")
'bb'
Step-by-Step Approach
- Handle the empty-string edge case up front, returning
""immediately. - A palindrome is symmetric around some center. That center is either a single
character (odd-length palindrome) or the gap between two adjacent characters
(even-length palindrome) — so every possible palindrome has exactly one of
2n - 1possible centers for a string of lengthn. - Write an
expand(left, right)helper that starts at a candidate center and grows outward one step at a time whiles[left] == s[right], stopping as soon as the characters mismatch or a boundary is hit. It returns the widest matching span found. - Loop over every index
ifrom 0 tolen(s) - 1, callingexpand(i, i)for the odd-length case centered oni, andexpand(i, i + 1)for the even-length case centered betweeniandi + 1. - Track the best (longest) span seen so far across all centers, keeping the first-found span on ties since iteration proceeds left to right.
- Return the substring corresponding to the best span found.
The key insight is that checking all 2n - 1 centers and expanding
outward from each is O(n²) total but far simpler to implement correctly than the O(n)
Manacher's algorithm, and is the expected approach for a medium-difficulty interview
question.
Reference solution
def longest_palindrome(s: str) -> str:
# expand around each center (odd and even length), O(n^2) time, O(1) space
if not s:
# empty-string edge case
return ""
# closure over s, grows outward while chars match
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
# +1/-1 corrects for the one-step overshoot past the mismatch
return left + 1, right - 1
best_start, best_end = 0, 0
for i in range(len(s)):
# odd-length center: single character
l1, r1 = expand(i, i)
# strict > keeps the earliest span on ties
if r1 - l1 > best_end - best_start:
best_start, best_end = l1, r1
# even-length center: gap between two characters
l2, r2 = expand(i, i + 1)
if r2 - l2 > best_end - best_start:
best_start, best_end = l2, r2
# +1 since best_end is an inclusive index
return s[best_start : best_end + 1]
Key Functions & Tricks
def expand(left, right) -> tuple[int, int]:— closure helper, grows outward one step at a time while characters match.- Two center types (odd vs. even) — every palindrome centers on a character or a gap; checking both covers all
2n - 1centers. if r1 - l1 > best_end - best_start:— strict>keeps the earliest-found span on ties.s[best_start : best_end + 1]—+1since slicing excludes the stop butbest_endis inclusive.if not s: return ""— guards the empty-string edge case up front.
How to Recognize This Pattern
Signal: any problem about the longest (or all) palindromic substrings within a string. If the phrase "palindrome" plus "longest" or "count all" shows up, expand around center is the go-to first approach to mention, since it's simple, O(n²), and correct for both odd and even-length cases if you remember to check both center types.
Common variations: counting the total number of palindromic substrings (accumulate a
counter inside expand instead of tracking a single best span); solving
it with interval DP (is_pal[i][j] built from smaller subproblems) which
generalizes better to some related problems; Manacher's algorithm for a true O(n)
solution when the input can be very large.
Common pitfall: only checking odd-length centers (expand(i, i)) and
forgetting the even-length case (expand(i, i + 1)), which silently
misses palindromes of even length like "bb" or "abba".