Count the palindromic substrings
Given a string s, return the number of its substrings that are palindromes. Substrings at different positions
count separately even if they are equal.
Examples
| Input | Output | Why |
|---|---|---|
s = "abc" | 3 | "a", "b", "c". |
s = "aaa" | 6 | Three "a", two "aa", one "aaa". |
s = "abba" | 6 | a, b, b, a, bb, abba. |
Constraints
- 1 ≤ s.length ≤ 1000
- Lowercase English letters
Hints
Hint 1
pal[i][j] = s[i] = s[j] and (j − i < 2 or pal[i + 1][j − 1]); count the true entries.
Hint 2
Or expand from each of the 2n − 1 centres: every step that keeps the ends equal is one more palindrome.
Where people lose marks
- Counting distinct palindromes instead of positions.
- Forgetting even-length centres.
Dry run on "abba"
Read it one frame at a time, the way you would trace the code on paper in an interview. Each frame shows the state after the step it describes.
-
Step 1 / 7sa0b1b2a3total1
Centre at 0: 1 palindrome.
-
Step 2 / 7sa0b1b2a3total1
Centre between 0 and 1: 0 palindromes.
-
Step 3 / 7sa0b1b2a3total2
Centre at 1: 1 palindrome.
-
Step 4 / 7sa0b1b2a3total4
Centre between 1 and 2: 2 palindromes.
-
Step 5 / 7sa0b1b2a3total5
Centre at 2: 1 palindrome.
-
Step 6 / 7sa0b1b2a3total5
Centre between 2 and 3: 0 palindromes.
-
Step 7 / 7sa0b1b2a3total6
Centre at 3: 1 palindrome.
How to think about it
The interval feasibility table pal[i][j] answers it directly: count its true entries. The same fact (matching ends
around a palindrome) without the table: from each of the 2n − 1 centres, expand outwards while the ends match, counting
one palindrome per successful step. Same O(n²) time, O(1) memory.
Complexity. Time O(n²) · Space O(1)
The solution, in six languages
Each one is compiled and run against the test table before it is published. Java is reviewed by hand.
def count_palindromes(s):
total = 0
for centre in range(2 * len(s) - 1): # characters and gaps
lo, hi = centre // 2, (centre + 1) // 2
while lo >= 0 and hi < len(s) and s[lo] == s[hi]:
total += 1 # s[lo..hi] is a palindrome
lo -= 1
hi += 1
return total#include <string>
int solve(std::string s) {
int n = s.size(), total = 0;
for (int c = 0; c < 2 * n - 1; ++c)
for (int lo = c / 2, hi = (c + 1) / 2; lo >= 0 && hi < n && s[lo] == s[hi]; --lo, ++hi) ++total;
return total;
}class Solution {
public int countPalindromes(String s) {
int n = s.length(), total = 0;
for (int c = 0; c < 2 * n - 1; c++)
for (int lo = c / 2, hi = (c + 1) / 2; lo >= 0 && hi < n && s.charAt(lo) == s.charAt(hi); lo--, hi++) total++;
return total;
}
}function countPalindromes(s) {
let total = 0;
for (let c = 0; c < 2 * s.length - 1; c++)
for (let lo = c >> 1, hi = (c + 1) >> 1; lo >= 0 && hi < s.length && s[lo] === s[hi]; lo--, hi++) total++;
return total;
}fn solve(s: &str) -> i64 {
let c: Vec<u8> = s.bytes().collect();
let n = c.len() as i64;
let mut total = 0;
for centre in 0..2 * n - 1 {
let (mut lo, mut hi) = (centre / 2, (centre + 1) / 2);
while lo >= 0 && hi < n && c[lo as usize] == c[hi as usize] {
total += 1;
lo -= 1;
hi += 1;
}
}
total
}import Data.Array
solve :: String -> Int
solve s = sum [expand (c `div` 2) ((c + 1) `div` 2) | c <- [0 .. 2 * n - 2]]
where
n = length s
a = listArray (0, n - 1) s
-- the number of palindromes around one centre
expand lo hi
| lo >= 0 && hi < n && a ! lo == a ! hi = 1 + expand (lo - 1) (hi + 1)
| otherwise = 0
Variants to try
- Count the distinct palindromic substrings (a palindromic tree, or hashing).
- Manacher's algorithm in O(n).
- Count palindromic subsequences (an interval DP with inclusion–exclusion).
Next problems
The fewest insertions to make a palindrome
Insert characters anywhere to make a string read the same backwards. Matching ends are free; otherwise insert a copy of one end and shrink the interval.
Open the problem → Easy10 minThe cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem → Medium15 minCan a subset reach the target?
Decide whether some subset of positive integers adds up to exactly the target. A boolean array over totals, filled downwards for each number.
Open the problem →Write a solution and run it against the real test table.
Keep going
The fewest insertions to make a palindrome
Insert characters anywhere to make a string read the same backwards. Matching ends are free; otherwise insert a copy of one end and shrink the interval.
Open the problem → Easy10 minThe cheapest way up a staircase
Each step has a cost; climb one or two steps at a time; start on step 0 or 1. Return the cheapest way past the top.
Open the problem → Medium15 minCan a subset reach the target?
Decide whether some subset of positive integers adds up to exactly the target. A boolean array over totals, filled downwards for each number.
Open the problem → Dynamic programmingThe pattern behind it
Write the recursion, notice the repeats, fill a table in an order that makes each entry final.
Read the pattern →Preparing for a real process? Quant interview preparation, or book a free 20-minute call.