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: