150NeetCode 150

104.Palindromic Substrings

MediumBlind 751-D Dynamic Programming · 6/12

Problem

Given a string s, return how many of its substrings are palindromes.

A substring is a contiguous, non-empty block of characters. Substrings at different positions count separately even if they contain the same characters (in "aaa", each single "a" counts).

Examples

Input:  s = "abc"
Output: 3
Explanation: "a", "b", "c".
Input:  s = "aaa"
Output: 6
Explanation: "a", "a", "a", "aa", "aa", "aaa".
Input:  s = "abba"
Output: 6
Explanation: "a", "b", "b", "a", "bb", "abba".

Constraints

  • 1 <= s.length <= 1000
  • s consists of lowercase English letters.

💡 Key Insight

This is Longest Palindromic Substring with "count" instead of "max". s[i..j] is a palindrome iff s[i] == s[j] and s[i+1..j-1] is a palindrome, so a DP over (i, j) counts them in O(n²). Equivalently, every palindrome has a unique centre (one of 2n - 1 characters or gaps), and expanding outward from a centre discovers the palindromes there one per successful step — O(n²) time and O(1) space. Manacher's radii p[i] give each centre's count directly as (p[i] + 1) / 2, for O(n) overall.

Brute Force

TimeO(n³)SpaceO(1).

Intuition

Enumerate all n(n+1)/2 substrings and test each one with two pointers.

Algorithm

  1. count = 0.
  2. For every i and every j >= i, if s[i..j] is a palindrome, count++.
  3. Return count.

Visualization

s = "aaa"
i=0: "a" ✓  "aa" ✓  "aaa" ✓
i=1: "a" ✓  "aa" ✓
i=2: "a" ✓
count = 6

Code

java
class Solution {
    public int countSubstrings(String s) {
        int n = s.length();
        int count = 0;
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                if (isPalindrome(s, i, j)) {
                    count++;
                }
            }
        }
        return count;
    }

    private boolean isPalindrome(String s, int lo, int hi) {
        while (lo < hi) {
            if (s.charAt(lo++) != s.charAt(hi--)) {
                return false;
            }
        }
        return true;
    }
}

Complexity

  • Time: O(n³) — O(n²) substrings, O(n) check each.
  • Space: O(1).

Complexity Comparison

Approach Time Space
Brute Force O(n³) O(1)
Top-Down Memoization O(n²) O(n²)
Bottom-Up Tabulation O(n²) O(n²)
Expand Around Center O(n²) O(1)
Manacher's Algorithm O(n) O(n)

Common Pitfalls

  • Counting only odd centres — "aa" has 3 palindromes, not 2.
  • De-duplicating by content (e.g. a HashSet<String>): identical substrings at different positions must each be counted.
  • Iterating i upward in the DP table, reading dp[i + 1][j - 1] before it is computed.
  • In Manacher, adding p[i] instead of (p[i] + 1) / 2 — that double-counts via the # positions.