Skip to main content

647 - Palindromic Substrings

Difficulty: Medium | Pattern: Expand Around Center | Company tags: Google, Amazon, Facebook, LinkedIn

Problem Statement

Given a string s, return the number of palindromic substrings in it.

A string is a palindrome when it reads the same backward as forward. A substring is a contiguous sequence of characters within the string.

Example 1:

Input: s = "abc"
Output: 3
Explanation: Three palindromic substrings: "a", "b", "c"

Example 2:

Input: s = "aaa"
Output: 6
Explanation: 6 palindromic substrings: "a", "a", "a", "aa", "aa", "aaa"

Constraints: 1 <= s.length <= 1000; s consists of lowercase English letters.

Approach: Expand Around Center — O(n²) time, O(1) space

Key insight: Same as LeetCode 5 (Longest Palindromic Substring). Every palindrome has a center. Expand around each possible center (each character for odd-length, each gap for even-length) and count how many palindromes each center generates.

def countSubstrings(s: str) -> int:
count = 0
n = len(s)

def expand(left, right):
nonlocal count
while left >= 0 and right < n and s[left] == s[right]:
count += 1
left -= 1
right += 1

for i in range(n):
expand(i, i) # odd-length palindromes centered at i
expand(i, i+1) # even-length palindromes centered between i and i+1

return count

Dry Run

s = "aaa"

CenterExpansion typePalindromes found
i=0, odd(0,0): "a" → count=1; expand (-1,1): out of bounds1
i=0, even(0,1): s[0]='a'==s[1]='a' → "aa" count=2; expand (-1,2): out of bounds1
i=1, odd(1,1): "a" count=3; expand(0,2): s[0]='a'==s[2]='a' → "aaa" count=4; expand(-1,3): out of bounds2
i=1, even(1,2): s[1]='a'==s[2]='a' → "aa" count=5; expand(0,3): out of bounds1
i=2, odd(2,2): "a" count=6; expand(1,3): out of bounds1
i=2, even(2,3): out of bounds0

Total: 6

Comparison with LeetCode 5

ProblemGoalKey difference
5 - Longest Palindromic SubstringFind the longest palindromeTrack start/end of longest
647 - Palindromic SubstringsCount all palindromesIncrement count on each expansion

The expand-around-center logic is identical — only what you track changes.

Alternative: DP — O(n²) time, O(n²) space

def countSubstrings(s: str) -> int:
n = len(s)
dp = [[False] * n for _ in range(n)]
count = 0

for length in range(1, n+1):
for i in range(n - length + 1):
j = i + length - 1
if s[i] == s[j] and (length <= 2 or dp[i+1][j-1]):
dp[i][j] = True
count += 1

return count

Complexity

ApproachTimeSpace
Expand around centerO(n²)O(1)
DPO(n²)O(n²)

Expand around center is preferred for its O(1) space.