Palindrome Substrings Count
Last Updated :
08 Mar, 2025
Given a string s, the task is to count all palindromic substrings of length more than one.
Examples:
Input: s = "abaab"
Output: 3
Explanation: Palindromic substrings with length greater than 1, are "aba", "aa", and "baab".
Input: s = "aaa"
Output: 3
Explanation: Palindromic substrings with length greater than 1, are "aa" , "aa" , "aaa" .
Input: s = "abbaeae"
Output: 4
Explanation: Palindromic substrings with length greater than 1, are "bb" , "abba" , "aea", "eae".
[Naive Approach] By Generating All Possible Substrings - O(n^3) Time and O(1) Space
The idea is to generate all possible substrings using two nested loops and for every substring check if it is palindrome or not.
C++
// C++ program to count all palindromic substring of
// given string by generating all possible substrings
#include <iostream>
#include <string>
using namespace std;
// Function to check if a substring
// s[i..j] is a palindrome
bool isPalindrome(string& s, int i, int j) {
while (i < j) {
if (s[i] != s[j]) return false;
i++;
j--;
}
return true;
}
int countPS(string& s) {
int n = s.length();
// Consider all possible substrings of lengths
// more than 1
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i+1; j < n; j++) {
// If substring from i to j is palindrome
// increment the result
if (isPalindrome(s, i, j))
res++;
}
}
return res;
}
int main() {
string s = "abaab";
cout << countPS(s);
return 0;
}
Java
// Java program to count all palindromic substring of
// given string by generating all possible substrings
class GfG {
// Function to check if a substring
// s[i..j] is a palindrome
static boolean isPalindrome(String s, int i, int j) {
while (i < j) {
if (s.charAt(i) != s.charAt(j)) return false;
i++;
j--;
}
return true;
}
static int countPS(String s) {
int n = s.length();
// Consider all possible substrings of lengths
// more than 1
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// If substring from i to j is palindrome
// increment the result
if (isPalindrome(s, i, j))
res++;
}
}
return res;
}
public static void main(String[] args) {
String s = "abaab";
System.out.println(countPS(s));
}
}
Python
# Python program to count all palindromic substring of
# given string by generating all possible substrings
# Function to check if a substring
# s[i..j] is a palindrome
def isPalindrome(s, i, j):
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True
def countPS(s):
n = len(s)
# Consider all possible substrings of lengths
# more than 1
res = 0
for i in range(n):
for j in range(i + 1, n):
# If substring from i to j is palindrome
# increment the result
if isPalindrome(s, i, j):
res += 1
return res
if __name__ == "__main__":
s = "abaab"
print(countPS(s))
C#
// C# program to count all palindromic substring of
// given string by generating all possible substrings
using System;
class GfG {
// Function to check if a substring
// s[i..j] is a palindrome
static bool isPalindrome(string s, int i, int j) {
while (i < j) {
if (s[i] != s[j]) return false;
i++;
j--;
}
return true;
}
static int countPS(string s) {
int n = s.Length;
// Consider all possible substrings of lengths
// more than 1
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// If substring from i to j is palindrome
// increment the result
if (isPalindrome(s, i, j))
res++;
}
}
return res;
}
static void Main() {
string s = "abaab";
Console.WriteLine(countPS(s));
}
}
JavaScript
// JavaScript program to count all palindromic substring
// of given string by generating all possible substrings
function isPalindrome(s, i, j) {
while (i < j) {
if (s[i] !== s[j]) return false;
i++;
j--;
}
return true;
}
function countPS(s) {
let n = s.length;
// Consider all possible substrings of lengths
// more than 1
let res = 0;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
// If substring from i to j is palindrome
// increment the result
if (isPalindrome(s, i, j))
res++;
}
}
return res;
}
// Driver Code
let s = "abaab";
console.log(countPS(s));
[Better Approach 1] Using Memoization - O(n^2) Time and O(n^2) Space
If we notice carefully, we can observe that this recursive solution holds the following two properties of Dynamic Programming:
1. Optimal Substructure: The solution for the problem isPalindrome(i, j) depends on the optimal solution of the subproblem isPalindrome(i + 1, j - 1). By solving the smaller substructures, we can efficiently find if the entire substring is a palindrome or not.
2. Overlapping Subproblems: We can see that we are computing the same subproblems multiple times, isPalindrome(i + 2, j - 2) will be computed in isPalindrome(i, j) as well as isPalindrome(i + 1, j - 1). This redundancy leads to overlapping subproblems.
- There are two parameters(i and j) that change in the recursive solution and then can go from 0 to n. So we create a 2D array of size n x n for memoization.
- We initialize this array as -1 to indicate nothing is computed initially. We first check if the value is -1, then only we make recursive calls.
- If the substring from i to j is a palindrome, we store memo[i][j] = 1, otherwise 0.
C++
// C++ program to count all palindromic substring of
// given string using memoization
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int isPalindrome(int i, int j, string& s,
vector<vector<int>>& memo) {
// One length string is always palindrome
if (i == j)
return 1;
// Two length string is plaindrome if
// both characters are same
if (j == i + 1 && s[i] == s[j])
return 1;
// if current substring is already checked
if (memo[i][j] != -1)
return memo[i][j];
// Check if the characters at i and j are equal
// and the substring inside is palindrome
memo[i][j] = (s[i] == s[j] &&
isPalindrome(i + 1, j - 1, s, memo));
return memo[i][j];
}
int countPS(string& s) {
int n = s.length();
// Memoization table
vector<vector<int>> memo(n, vector<int>(n, -1));
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Check if the substring is palindrome
if (isPalindrome(i, j, s, memo)) {
res++;
}
}
}
return res;
}
int main() {
string s = "abaab";
cout << countPS(s);
return 0;
}
Java
// Java program to count all palindromic substring of given
// string using memoization
import java.util.Arrays;
class GfG {
static int isPalindrome(int i, int j, String s,
int[][] memo) {
// One length string is always palindrome
if (i == j)
return 1;
// Two length string is palindrome if
// both characters are same
if (j == i + 1 && s.charAt(i) == s.charAt(j))
return 1;
// if current substring is already checked
if (memo[i][j] != -1)
return memo[i][j];
// Check if the characters at i and j are equal
// and the substring inside is palindrome
if(s.charAt(i) == s.charAt(j) &&
isPalindrome(i + 1, j - 1, s, memo) == 1)
memo[i][j] = 1;
else
memo[i][j] = 0;
return memo[i][j];
}
static int countPS(String s) {
int n = s.length();
// Memoization table
int[][] memo = new int[n][n];
for (int[] row : memo) {
Arrays.fill(row, -1);
}
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Check if the substring is palindrome
if (isPalindrome(i, j, s, memo) == 1) {
res++;
}
}
}
return res;
}
public static void main(String[] args) {
String s = "abaab";
System.out.println(countPS(s));
}
}
Python
# Python program to count all palindromic substrings of
# a given string using memoization
def isPalindrome(i, j, s, memo):
# One length string is always palindrome
if i == j:
return 1
# Two length string is palindrome if
# both characters are same
if j == i + 1 and s[i] == s[j]:
return 1
# if current substring is already checked
if memo[i][j] != -1:
return memo[i][j]
# Check if the characters at i and j are equal
# and the substring inside is palindrome
if s[i] == s[j] and isPalindrome(i + 1, j - 1, s, memo) == 1:
memo[i][j] = 1
else:
memo[i][j] = 0
return memo[i][j]
def countPS(s):
n = len(s)
# Memoization table
memo = [[-1 for i in range(n)] for i in range(n)]
res = 0
for i in range(n):
for j in range(i + 1, n):
# Check if the substring is palindrome
if isPalindrome(i, j, s, memo) == 1:
res += 1
return res
if __name__ == "__main__":
s = "abaab"
print(countPS(s))
C#
// C# program to count all palindromic substrings of
// a given string using memoization
using System;
class GfG {
static int IsPalindrome(int i, int j, string s,
int[,] memo) {
// One length string is always palindrome
if (i == j)
return 1;
// Two length string is palindrome if
// both characters are same
if (j == i + 1 && s[i] == s[j])
return 1;
// if current substring is already checked
if (memo[i, j] != -1)
return memo[i, j];
// Check if the characters at i and j are equal
// and the substring inside is palindrome
if (s[i] == s[j] &&
IsPalindrome(i + 1, j - 1, s, memo) == 1) {
memo[i, j] = 1;
}
else {
memo[i, j] = 0;
}
return memo[i, j];
}
static int CountPS(string s) {
int n = s.Length;
// Memoization table
int[,] memo = new int[n, n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
memo[i, j] = -1;
}
}
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// Check if the substring is palindrome
if (IsPalindrome(i, j, s, memo) == 1) {
res++;
}
}
}
return res;
}
static void Main() {
string s = "abaab";
Console.WriteLine(CountPS(s));
}
}
JavaScript
// JavaScript program to count all palindromic substrings of
// a given string using memoization
function isPalindrome(i, j, s, memo) {
// One length string is always palindrome
if (i === j)
return 1;
// Two length string is palindrome if
// both characters are same
if (j === i + 1 && s[i] === s[j])
return 1;
// if current substring is already checked
if (memo[i][j] !== -1)
return memo[i][j];
// Check if the characters at i and j are equal
// and the substring inside is palindrome
if (s[i] === s[j] &&
isPalindrome(i + 1, j - 1, s, memo) === 1)
memo[i][j] = 1;
else
memo[i][j] = 0;
return memo[i][j];
}
function countPS(s) {
const n = s.length;
// Memoization table
const memo = Array.from({ length: n }, () => Array(n).fill(-1));
let res = 0;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
// Check if the substring is palindrome
if (isPalindrome(i, j, s, memo) === 1) {
res++;
}
}
}
return res;
}
// Driver Code
const s = "abaab";
console.log(countPS(s));
[Better Approach 2] Using Bottom-Up DP (Tabulation) - O(n^2) Time and O(n^2) Space
We create a dp array of size n x n. However, we cannot simply fill the dp table from i = 0 to n-1 and j from i to n-1. To compute the value for (i, j), we need the value from (i+1, j-1). Similar to Matrix Chain Multiplication, we need to fill the table diagonally using a gap variable.
1. Base Cases:
- A single character string is always palindrome, i.e. dp[i][i] = true.
- Strings having two characters are palindrome, if both the characters are same. i.e. dp[i][i+1] = true if s[i] == s[i+1].
2. Any substring s[i...j] will be palindrome if:
- If first and last characters of string are same
- Remaining substring (excluding first and last character) is palindrome. I.e. dp[i+1][j-1] = true.
Illustration:
C++
// C++ program to count all palindromic substring of
// given string using bottom up DP
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int countPS(string& s) {
int n = s.length();
int res = 0;
vector<vector<bool>> dp(n, vector<bool>(n, false));
// One length string is always palindrome
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// Two length string is plaindrome if
// both characters are same
for (int i = 0; i < n - 1; i++) {
if (s[i] == s[i + 1]) {
dp[i][i + 1] = true;
res++;
}
}
// Handle palindromes of length
// greater than 2 (gap >= 2)
for (int gap = 2; gap < n; gap++) {
for (int i = 0; i < n - gap; i++) {
int j = i + gap;
// Check if the current string is a palindrome
if (s[i] == s[j] && dp[i + 1][j - 1]) {
dp[i][j] = true;
res++;
}
}
}
return res;
}
int main() {
string s = "abaab";
cout << countPS(s) << endl;
return 0;
}
Java
// Java program to count all palindromic substrings of
// given string using bottom-up DP
import java.util.*;
class GfG {
static int countPS(String s) {
int n = s.length();
int res = 0;
boolean[][] dp = new boolean[n][n];
// One length string is always palindrome
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// Two length string is palindrome if
// both characters are same
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
dp[i][i + 1] = true;
res++;
}
}
// Handle palindromes of length greater than 2
for (int gap = 2; gap < n; gap++) {
for (int i = 0; i < n - gap; i++) {
int j = i + gap;
// Check if the current string is a palindrome
if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
dp[i][j] = true;
res++;
}
}
}
return res;
}
public static void main(String[] args) {
String s = "abaab";
System.out.println(countPS(s));
}
}
Python
# Python program to count all palindromic substrings of
# given string using bottom-up DP
def countPS(s):
n = len(s)
res = 0
dp = [[False] * n for i in range(n)]
# One length string is always palindrome
for i in range(n):
dp[i][i] = True
# Two length string is palindrome if
# both characters are same
for i in range(n - 1):
if s[i] == s[i + 1]:
dp[i][i + 1] = True
res += 1
# Handle palindromes of length
# greater than 2 (gap >= 2)
for gap in range(2, n):
for i in range(n - gap):
j = i + gap
# Check if the current string is a palindrome
if s[i] == s[j] and dp[i + 1][j - 1]:
dp[i][j] = True
res += 1
return res
if __name__ == "__main__":
s = "abaab"
print(countPS(s))
C#
// C# program to count all palindromic substrings of
// given string using bottom-up DP
using System;
class GfG {
static int countPS(string s) {
int n = s.Length;
int res = 0;
bool[,] dp = new bool[n, n];
// One length string is always palindrome
for (int i = 0; i < n; i++) {
dp[i, i] = true;
}
// Two length string is palindrome if
// both characters are same
for (int i = 0; i < n - 1; i++) {
if (s[i] == s[i + 1]) {
dp[i, i + 1] = true;
res++;
}
}
// Handle palindromes of length
// greater than 2 (gap >= 2)
for (int gap = 2; gap < n; gap++) {
for (int i = 0; i < n - gap; i++) {
int j = i + gap;
// Check if the current string is a palindrome
if (s[i] == s[j] && dp[i + 1, j - 1]) {
dp[i, j] = true;
res++;
}
}
}
return res;
}
static void Main() {
string s = "abaab";
Console.WriteLine(countPS(s));
}
}
JavaScript
// JavaScript program to count all palindromic substrings of
// given string using bottom-up DP
function countPS(s) {
const n = s.length;
let res = 0;
const dp = Array.from({ length: n }, () => Array(n).fill(false));
// One length string is always palindrome
for (let i = 0; i < n; i++) {
dp[i][i] = true;
}
// Two length string is palindrome if
// both characters are same
for (let i = 0; i < n - 1; i++) {
if (s[i] === s[i + 1]) {
dp[i][i + 1] = true;
res++;
}
}
// Handle palindromes of length
// greater than 2 (gap >= 2)
for (let gap = 2; gap < n; gap++) {
for (let i = 0; i < n - gap; i++) {
const j = i + gap;
// Check if the current string is a palindrome
if (s[i] === s[j] && dp[i + 1][j - 1]) {
dp[i][j] = true;
res++;
}
}
}
return res;
}
// Driver Code
const s = "abaab";
console.log(countPS(s));
[Expected Approach] Using Center Expansion - O(n^2) Time and O(1) Space
We can further optimize this problem using the center expansion technique. We have used this idea in Longest Palindromic Substring also. In this approach, we consider every character in the string as the center for odd-length palindromes and as one of the two centers for even-length palindromes. We then expand the substring outwards, checking the elements at both ends. For a complete implementation of this approach, refer this article - Count All Palindrome Sub-Strings using Center Expansion.
Related article:
Similar Reads
DSA Tutorial - Learn Data Structures and Algorithms
DSA (Data Structures and Algorithms) is the study of organizing data efficiently using data structures like arrays, stacks, and trees, paired with step-by-step procedures (or algorithms) to solve problems effectively. Data structures manage how data is stored and accessed, while algorithms focus on
7 min read
Quick Sort
QuickSort is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array. It works on the principle of divide and conquer, breaking down the problem into s
12 min read
Merge Sort - Data Structure and Algorithms Tutorials
Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer approach. It works by recursively dividing the input array into two halves, recursively sorting the two halves and finally merging them back together to obtain the sorted array. Merge
14 min read
Bubble Sort Algorithm
Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case time complexity are quite high.We sort the array using multiple passes. After the fir
8 min read
Breadth First Search or BFS for a Graph
Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
15+ min read
Data Structures Tutorial
Data structures are the fundamental building blocks of computer programming. They define how data is organized, stored, and manipulated within a program. Understanding data structures is very important for developing efficient and effective algorithms. What is Data Structure?A data structure is a st
2 min read
Binary Search Algorithm - Iterative and Recursive Implementation
Binary Search Algorithm is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N). Binary Search AlgorithmConditions to apply Binary Searc
15 min read
Insertion Sort Algorithm
Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list. It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards. T
9 min read
Dijkstra's Algorithm to find Shortest Paths from a Source to all
Given a weighted undirected graph represented as an edge list and a source vertex src, find the shortest path distances from the source vertex to all other vertices in the graph. The graph contains V vertices, numbered from 0 to V - 1.Note: The given graph does not contain any negative edge. Example
12 min read
Selection Sort
Selection Sort is a comparison-based sorting algorithm. It sorts an array by repeatedly selecting the smallest (or largest) element from the unsorted portion and swapping it with the first unsorted element. This process continues until the entire array is sorted.First we find the smallest element an
8 min read