Open In App

All distinct palindromic sub-strings of a given string

Last Updated : 11 Mar, 2025
Comments
Improve
Suggest changes
29 Likes
Like
Report

Given a string str of lowercase ASCII characters. The task is to find all the distinct continuous palindromic sub-strings which are present in the string str.

Examples: 

Input: str = "abaaa"
Output: [ "a", "aa", "aaa", "aba", "b" ]
Explanation: All 5 distinct continuous palindromic sub-strings are listed above.

Input: str = "geek"
Output: [ "e", "ee", "g", "k" ]
Explanation: All 4 distinct continuous palindromic sub-strings are listed above.

[Naive Approach - 1] - Generating All Substrings - O(n ^ 3) Time and O(n ^ 2) Space

The idea is to generate all possible substrings and find all the palindromic substrings, and use set to store all the distinct one.

C++
#include <bits/stdc++.h>
using namespace std;

// Function to find all distinct palindrome 
// substrings in a given string
vector<string> palindromicSubstr(string &str) {
    int n = str.length();

    // Create a set to store the result
    unordered_set<string> result;

    // generate all substrings
    for(int i = 0; i < n; i++) {

        // to store the substring
        string cur = "";

        for(int j = i; j < n; j++) {
            cur += str[j];

            // check if cur is palindrome
            int l = 0, r = cur.length() - 1;
            bool isPalindrome = true;
            while(l < r) {
                if(cur[l] != cur[r]) {
                    isPalindrome = false;
                    break;
                }
                l++;
                r--;
            }

            // if cur is palindrome, 
            // insert it into the set
            if(isPalindrome) {
                result.insert(cur);
            }
        }
    }

    // Convert the set to a vector
    vector<string> res(result.begin(), result.end());

    return res;
}

int main() {
    string str = "abaaa";
    vector<string> result = palindromicSubstr(str);
    for(string s : result)
        cout << s << " ";
    return 0;
}
Java Python C# JavaScript

Output
a aaa aba b aa 

[Naive Approach - 2] - Using Dynamic Programming and Set - O(n ^ 3) Time and O(n ^ 2) Space

The idea is to use Dynamic Programming to find all palindromic substrings and set to store all the distinct one. To do so, create a 2d array dp[][] of order n * n, where dp[i][j] is True if substring s[i..j] is palindrome. Any substring s[i..j] will be palindromic if s[i] == s[j] and dp[i+1][j-1] is True. Thus run a nested loop where the outer loop marks the start and inner loop marks the end of substring.

Follow the below given steps:

  • Declare a Boolean 2-D array and fill it diagonally.
  • Now, check for every possible length, i.e. 0, 1, 2, and so on.
  • If gap=0, that means there is only one element and we put  true since  a single character is palindrome
  • if gap = 1, we check whether extremes are same and if so we put true, else false;
  • Else for any other value of gap, we check if extremes are same and dp[i+1][j-1] yields true, if so then we put true, else false.
  • Each time when a true is encountered, add the string in the set data structure.
  • At last, store all the strings in the set, in an array, and return it.
C++
#include <bits/stdc++.h>
using namespace std;

// Function to find all distinct palindrome 
// substrings in a given string
vector<string> palindromicSubstr(string &str) {
    int n = str.length();

    // Create a 2D array
    vector<vector<bool>> dp(n, vector<bool>(n, false));

    // Create a set to store the result
    unordered_set<string> result;

    // Traverse the string
    for (int gap = 0; gap < n; gap++) {
        for (int i = 0, j = gap; j < n; i++, j++) {

            // If the gap is 0, it is a palindrome
            if (gap == 0)
                dp[i][j] = true;

            // If the gap is 1, check if 
            // the characters are the same
            else if (gap == 1)
                dp[i][j] = (str[i] == str[j]);

            // check if the characters are the same
            // and the inner substring is a palindrome
            else
                dp[i][j] = (str[i] == str[j] && dp[i + 1][j - 1]);

            // If the substring is a palindrome
            // insert it into the set
            if (dp[i][j])
                result.insert(str.substr(i, j - i + 1));
        }
    }

    // Convert the set to a vector
    vector<string> res(result.begin(), result.end());

    return res;
}

int main() {
    string str = "abaaa";
    vector<string> result = palindromicSubstr(str);
    for(string s : result)
        cout << s << " ";
    return 0;
}
Java Python C# JavaScript

Output
a b aa aaa aba 

[Better Approach] - Using Manacher's Algorithm and Hash Set - O(n ^ 2) Time and O(n ^ 2) Space

The idea is to use Manacher's Algorithm to find all palindromic substrings and set to store all the distinct one.

Follow the below given steps:

  • Consider each character as a pivot and expand on both sides to find the longest odd-length and even-length palindromes centered at that character; store these lengths in two separate arrays.
  • For every pivot, generate the actual palindromic substrings using the computed lengths.
  • Insert each found palindrome, along with all single characters, into a set so that only distinct palindromic substrings are kept.
  • Finally, store all the palindromes stored in the set in an array and return it.
C++
#include <bits/stdc++.h>
using namespace std;

// Function to find all distinct palindrome 
// substrings in a given string
vector<string> palindromicSubstr(string &str) {
    int n = str.length();

    // Create a set to store the result
    unordered_set<string> result;
  
    // table for storing results of 
    // odd even length subarrays
    vector<vector<int>> dp(2, vector<int>(n + 1, 0));

    // store all the palindromic substrings
    // of length 1 in the set
    for (int i = 0; i < n; i++)
        result.insert(str.substr(i, 1));

    // insert 'guards' to iterate easily over str
    str = "@" + str + "#";

    for (int j = 0; j <= 1; j++) {

        // length of 'palindrome radius' 
        int rp = 0;  
        dp[j][0] = 0;

        int i = 1;
        while (i <= n) {

            // expand palindrome centered at i 
            while (str[i - rp - 1] == str[i + j + rp])
                rp++;

            // Assign the found palindromic length 
            // to odd/even length array 
            dp[j][i] = rp;

            int k = 1;
            while ((dp[j][i - k] != rp - k) && (k < rp)) {
                dp[j][i + k] = min(dp[j][i - k], rp - k);
                k++;
            }

            // reset the length of palindromic radius
            rp = max(rp - k, 0);
            i += k;
        }
    }
  
    // remove 'guards' 
    str = str.substr(1, n); 

    // store the results in a set
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= 1; j++) {
            for (int rp = dp[j][i]; rp > 0; rp--) {
                result.insert(str.substr(i - rp - 1, 2 * rp + j));
            }
        }
    }
    
    // Convert the set to a vector
    vector<string> res(result.begin(), result.end());
    return res;
} 
  
int main() {
    string str = "abaaa";
    vector<string> result = palindromicSubstr(str);
    for(string str : result)
        cout << str << " ";
    return 0;
}
Java Python C# JavaScript

Output
a b aaa aba aa 

[Expected Approach] - Using Dynamic Programming and KMP Algorithm - O(n^2) Time and O(n^2) Space

The idea is to identify all palindromic substrings in a given string using a dynamic programming method, then eliminate duplicates by leveraging the KMP algorithm, and finally print the distinct palindromes along with their count.

Follow the below given steps:

  • First, for every possible substring, use dynamic programming to check if it is a palindrome.
  • Next, for every index starting from 0, apply the KMP algorithm to compare prefixes and suffixes. If a substring is both a palindrome and its prefix matches its suffix, mark it (for example, by setting the corresponding dp value to false) so that duplicate occurrences are removed.
  • Finally, iterate over all substrings and print those that remain marked as palindromic in the dp array; the number of such entries gives the total count of distinct palindromic substrings.
C++
#include <bits/stdc++.h>
using namespace std;

// Function to find all distinct palindrome 
// substrings in a given string
vector<string> palindromicSubstr(string &str) {
    int n = str.length();

    // Create a 2D array
    vector<vector<bool>> dp(n, vector<bool>(n, false));

    for (int i = 0; i < n; i++) {

        // base case every char is palindrome
        dp[i][i] = 1;

        // check for every substring of length 2
        if (i < n && str[i] == str[i + 1]) {
            dp[i][i + 1] = 1;
        }
    }

    // check every substring of length 
    // greater than 2 for palindrome
    for (int len = 3; len <= n; len++) {
        for (int i = 0; i + len - 1 < n; i++) {
            if (str[i] == str[i + (len - 1)]
                && dp[i + 1][i + (len - 1) - 1]) {
                dp[i][i + (len - 1)] = true;
            }
        }
    }

    // create an array of size n
    // to operate the kmp algorithm
    vector<int> kmp(n, 0);

    for (int i = 0; i < n; i++) {

        // starting kmp for every i from 0 to n-1
        int j = 0, k = 1;

        while (k + i < n) {
            if (str[j + i] == str[k + i]) {

                // make suffix to be false, if this suffix is 
                // palindrome then it is included in prefix
                dp[k + i - j][k + i] = false;
                kmp[k++] = ++j;
            }
            else if (j > 0) {
                j = kmp[j - 1];
            }
            else {
                kmp[k++] = 0;
            }
        }
    }
    
    // Create an array to store the result
    vector<string> result;

    for (int i = 0; i < n; i++) {

        // to store the current string
        string cur;
        for (int j = i; j < n; j++) {
            cur += str[j];
            if (dp[i][j]) {
                result.push_back(cur);
            }
        }
    }
    return result;
}

int main() {
    string str = "abaaa";
    vector<string> result = palindromicSubstr(str);
    for(string s : result)
        cout << s << " ";
    return 0;
}
Java Python C# JavaScript

Output
a aba b aa aaa 

[Alternate Approach] - Using Center Expansion and Set - O(n ^ 2) Time and O(n ^ 2) Space

The idea is to use center expansion technique to find all even and odd length palindromic substrings separately, and then store them in a set to find the unique palindromic substrings.

C++
#include <bits/stdc++.h>
using namespace std;

// Function to find all distinct palindrome 
// substrings in a given string
vector<string> palindromicSubstr(string &str) {
    int n = str.length();

    // Create a set to store the result
    unordered_set<string> result;

    // Check for odd length palindromes
    for (int i = 0; i < n; i++) {
        int left = i, right = i;
        while (left >= 0 && right < n && str[left] == str[right]) {

            // Add the palindrome substring
            result.insert(str.substr(left, right - left + 1));
            left--, right++;
        }
    }

    // Check for even length palindromes
    for (int i = 0; i < n - 1; i++) {
        int left = i, right = i + 1;
        while (left >= 0 && right < n && str[left] == str[right]) {

            // Add the palindrome substring
            result.insert(str.substr(left, right - left + 1));
            left--, right++;
        }
    }

    // Convert the set to a vector
    vector<string> res(result.begin(), result.end());

    return res;
}

int main() {
    string str = "abaaa";
    vector<string> result = palindromicSubstr(str);
    for(string str : result)
        cout << str << " ";
    return 0;
}
Java Python C# JavaScript

Output
aa a b aba aaa 

Related Article: 
Count All Palindrome Sub-Strings in a String


Next Article

Similar Reads