Palindrome Substrings Count (original) (raw)

Given a string **s, find the total number of palindromic substrings of length greater than or equal to 2 present in the string.
A substring is palindromic if it reads the same forwards and backwards.

**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".

Table of Content

[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 #include 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 i**sPalindrome(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.

// C++ program to count all palindromic substring of // given string using memoization

#include #include #include using namespace std;

int isPalindrome(int i, int j, string& s, vector<vector>& 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 #include #include

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 - Continued article

This problem can be solved more efficiently using Manacher’s algorithm or the center expansion technique.
See: Count All Palindrome Sub-Strings Set 2

**Related article: