Longest Palindromic Substring
Expand around each center (n odd-center, n-1 even-center); track the longest match.
4 min read
string expand-around-center dp
Problem#
Return the longest palindromic substring of s.
Examples#
"babad"→"bab"or"aba"."cbbd"→"bb";"a"→"a".
Constraints#
1 <= s.length <= 1000.
Approach#
Expand around 2n - 1 centers (each position and each gap between positions). For each center, walk outward while both sides match; record the longest.
Solution#
class Solution {public: string longestPalindrome(string s) { int n = s.size(), bestStart = 0, bestLen = 1; auto expand = [&](int l, int r) { while (l >= 0 && r < n && s[l] == s[r]) { --l; ++r; } int len = r - l - 1; if (len > bestLen) { bestLen = len; bestStart = l + 1; } }; for (int i = 0; i < n; ++i) { expand(i, i); expand(i, i + 1); } return s.substr(bestStart, bestLen); }};func longestPalindrome(s string) string { n := len(s) bestStart, bestLen := 0, 1 expand := func(l, r int) { for l >= 0 && r < n && s[l] == s[r] { l-- r++ } length := r - l - 1 if length > bestLen { bestLen = length bestStart = l + 1 } } for i := 0; i < n; i++ { expand(i, i) expand(i, i+1) } return s[bestStart : bestStart+bestLen]}class Solution: def longestPalindrome(self, s: str) -> str: n = len(s) best_start, best_len = 0, 1
def expand(l: int, r: int) -> None: nonlocal best_start, best_len while l >= 0 and r < n and s[l] == s[r]: l -= 1 r += 1 length = r - l - 1 if length > best_len: best_len = length best_start = l + 1
for i in range(n): expand(i, i) expand(i, i + 1) return s[best_start:best_start + best_len]function longestPalindrome(s) { const n = s.length; let bestStart = 0, bestLen = 1; const expand = (l, r) => { while (l >= 0 && r < n && s[l] === s[r]) { l--; r++; } const len = r - l - 1; if (len > bestLen) { bestLen = len; bestStart = l + 1; } }; for (let i = 0; i < n; i++) { expand(i, i); expand(i, i + 1); } return s.slice(bestStart, bestStart + bestLen);}class Solution { private int bestStart, bestLen;
public String longestPalindrome(String s) { int n = s.length(); bestStart = 0; bestLen = 1; for (int i = 0; i < n; i++) { expand(s, i, i); expand(s, i, i + 1); } return s.substring(bestStart, bestStart + bestLen); }
private void expand(String s, int l, int r) { int n = s.length(); while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) { l--; r++; } int len = r - l - 1; if (len > bestLen) { bestLen = len; bestStart = l + 1; } }}function longestPalindrome(s: string): string { const n = s.length; let bestStart = 0, bestLen = 1; const expand = (l: number, r: number): void => { while (l >= 0 && r < n && s[l] === s[r]) { l--; r++; } const len = r - l - 1; if (len > bestLen) { bestLen = len; bestStart = l + 1; } }; for (let i = 0; i < n; i++) { expand(i, i); expand(i, i + 1); } return s.slice(bestStart, bestStart + bestLen);}Editorial#
Expanding around centers covers both odd and even palindromes uniformly. Manacher’s algorithm achieves O(n) but is rarely needed inside the n <= 1000 constraint; the simple expansion is O(n^2) and one-pass clear.
Complexity#
- Time:
O(n^2). - Space:
O(1).
Concept revision#
Related#