Find all distinct palindromic sub-strings of a given string
Given a string of lowercase ASCII characters, find all distinct continuous palindromic sub-strings of it.
Examples:
Input: str = "abaaa" Output: Below are 5 palindrome sub-strings a aa aaa aba b Input: str = "geek" Output: Below are 4 palindrome sub-strings e ee g k
Method 1:
Step 1: Finding all palindromes using modified Manacher’s algorithm:
Considering each character as a pivot, expand on both sides to find the length of both even and odd length palindromes centered at the pivot character under consideration and store the length in the 2 arrays (odd & even).
Time complexity for this step is O(n^2)
Step 2: Inserting all the found palindromes in a HashMap:
Insert all the palindromes found from the previous step into a HashMap. Also insert all the individual characters from the string into the HashMap (to generate distinct single letter palindromic sub-strings).
Time complexity of this step is O(n^3) assuming that the hash insert search takes O(1) time. Note that there can be at most O(n^2) palindrome sub-strings of a string. In below C++ code ordered hashmap is used where the time complexity of insert and search is O(Logn). In C++, ordered hashmap is implemented using Red Black Tree.
Step 3: Printing the distinct palindromes and number of such distinct palindromes:
The last step is to print all values stored in the HashMap (only distinct elements will be hashed due to the property of HashMap). The size of the map gives the number of distinct palindromic continuous sub-strings.
Below is the implementation of the above idea.
C++
// C++ program to find all distinct palindrome sub-strings // of a given string #include <iostream> #include <map> using namespace std; // Function to print all distinct palindrome sub-strings of s void palindromeSubStrs(string s) { map<string, int > m; int n = s.size(); // table for storing results (2 rows for odd- // and even-length palindromes int R[2][n+1]; // Find all sub-string palindromes from the given input // string insert 'guards' to iterate easily over s s = "@" + s + "#" ; for ( int j = 0; j <= 1; j++) { int rp = 0; // length of 'palindrome radius' R[j][0] = 0; int i = 1; while (i <= n) { // Attempt to expand palindrome centered at i while (s[i - rp - 1] == s[i + j + rp]) rp++; // Incrementing the length of palindromic // radius as and when we find valid palindrome // Assigning the found palindromic length to odd/even // length array R[j][i] = rp; int k = 1; while ((R[j][i - k] != rp - k) && (k < rp)) { R[j][i + k] = min(R[j][i - k],rp - k); k++; } rp = max(rp - k,0); i += k; } } // remove 'guards' s = s.substr(1, n); // Put all obtained palindromes in a hash map to // find only distinct palindromess m[string(1, s[0])]=1; for ( int i = 1; i <= n; i++) { for ( int j = 0; j <= 1; j++) for ( int rp = R[j][i]; rp > 0; rp--) m[s.substr(i - rp - 1, 2 * rp + j)]=1; m[string(1, s[i])]=1; } //printing all distinct palindromes from hash map cout << "Below are " << m.size()-1 << " palindrome sub-strings" ; map<string, int >::iterator ii; for (ii = m.begin(); ii!=m.end(); ++ii) cout << (*ii).first << endl; } // Driver program int main() { palindromeSubStrs( "abaaa" ); return 0; } |
Java
// Java program to find all distinct palindrome // sub-strings of a given string import java.util.Map; import java.util.TreeMap; public class GFG { // Function to print all distinct palindrome // sub-strings of s static void palindromeSubStrs(String s) { //map<string, int> m; TreeMap<String , Integer> m = new TreeMap<>(); int n = s.length(); // table for storing results (2 rows for odd- // and even-length palindromes int [][] R = new int [ 2 ][n+ 1 ]; // Find all sub-string palindromes from the // given input string insert 'guards' to // iterate easily over s s = "@" + s + "#" ; for ( int j = 0 ; j <= 1 ; j++) { int rp = 0 ; // length of 'palindrome radius' R[j][ 0 ] = 0 ; int i = 1 ; while (i <= n) { // Attempt to expand palindrome centered // at i while (s.charAt(i - rp - 1 ) == s.charAt(i + j + rp)) rp++; // Incrementing the length of // palindromic radius as and // when we find valid palindrome // Assigning the found palindromic length // to odd/even length array R[j][i] = rp; int k = 1 ; while ((R[j][i - k] != rp - k) && (k < rp)) { R[j][i + k] = Math.min(R[j][i - k], rp - k); k++; } rp = Math.max(rp - k, 0 ); i += k; } } // remove 'guards' s = s.substring( 1 , s.length()- 1 ); // Put all obtained palindromes in a hash map to // find only distinct palindromess m.put(s.substring( 0 , 1 ), 1 ); for ( int i = 1 ; i < n; i++) { for ( int j = 0 ; j <= 1 ; j++) for ( int rp = R[j][i]; rp > 0 ; rp--) m.put(s.substring(i - rp - 1 , i - rp - 1 + 2 * rp + j), 1 ); m.put(s.substring(i, i + 1 ), 1 ); } // printing all distinct palindromes from // hash map System.out.println( "Below are " + (m.size()) + " palindrome sub-strings" ); for (Map.Entry<String, Integer> ii:m.entrySet()) System.out.println(ii.getKey()); } // Driver program public static void main(String args[]) { palindromeSubStrs( "abaaa" ); } } // This code is contributed by Sumit Ghosh |
Python3
# Python program Find all distinct palindromic sub-strings # of a given string # Function to print all distinct palindrome sub-strings of s def palindromeSubStrs(s): m = dict () n = len (s) # table for storing results (2 rows for odd- # and even-length palindromes R = [[ 0 for x in range (n + 1 )] for x in range ( 2 )] # Find all sub-string palindromes from the given input # string insert 'guards' to iterate easily over s s = "@" + s + "#" for j in range ( 2 ): rp = 0 # length of 'palindrome radius' R[j][ 0 ] = 0 i = 1 while i < = n: # Attempt to expand palindrome centered at i while s[i - rp - 1 ] = = s[i + j + rp]: rp + = 1 # Incrementing the length of palindromic # radius as and when we find valid palindrome # Assigning the found palindromic length to odd/even # length array R[j][i] = rp k = 1 while (R[j][i - k] ! = rp - k) and (k < rp): R[j][i + k] = min (R[j][i - k], rp - k) k + = 1 rp = max (rp - k, 0 ) i + = k # remove guards s = s[ 1 : len (s) - 1 ] # Put all obtained palindromes in a hash map to # find only distinct palindrome m[s[ 0 ]] = 1 for i in range ( 1 ,n): for j in range ( 2 ): for rp in range (R[j][i], 0 , - 1 ): m[s[i - rp - 1 : i - rp - 1 + 2 * rp + j]] = 1 m[s[i]] = 1 # printing all distinct palindromes from hash map print ( "Below are " + str ( len (m)) + " pali sub-strings" ) for i in m: print (i) # Driver program palindromeSubStrs( "abaaa" ) # This code is contributed by BHAVYA JAIN and ROHIT SIKKA |
C#
// C# program to find all distinct palindrome // sub-strings of a given string using System; using System.Collections.Generic; class GFG { // Function to print all distinct palindrome // sub-strings of s public static void palindromeSubStrs( string s) { //map<string, int> m; Dictionary < string , int > m = new Dictionary < string , int > (); int n = s.Length; // table for storing results (2 rows for odd- // and even-length palindromes int [, ] R = new int [2, n + 1]; // Find all sub-string palindromes from the // given input string insert 'guards' to // iterate easily over s s = "@" + s + "#" ; for ( int j = 0; j <= 1; j++) { int rp = 0; // length of 'palindrome radius' R[j, 0] = 0; int i = 1; while (i <= n) { // Attempt to expand palindrome centered // at i while (s[i - rp - 1] == s[i + j + rp]) // Incrementing the length of // palindromic radius as and // when we find valid palindrome rp++; // Assigning the found palindromic length // to odd/even length array R[j, i] = rp; int k = 1; while ((R[j, i - k] != rp - k) && k < rp) { R[j, i + k] = Math.Min(R[j, i - k], rp - k); k++; } rp = Math.Max(rp - k, 0); i += k; } } // remove 'guards' s = s.Substring(1); // Put all obtained palindromes in a hash map to // find only distinct palindromess if (!m.ContainsKey(s.Substring(0, 1))) m.Add(s.Substring(0, 1), 1); else m[s.Substring(0, 1)]++; for ( int i = 1; i < n; i++) { for ( int j = 0; j <= 1; j++) for ( int rp = R[j, i]; rp > 0; rp--) { if (!m.ContainsKey(s.Substring(i - rp - 1, 2 * rp + j))) m.Add(s.Substring(i - rp - 1, 2 * rp + j), 1); else m[s.Substring(i - rp - 1, 2 * rp + j)]++; } if (!m.ContainsKey(s.Substring(i, 1))) m.Add(s.Substring(i, 1), 1); else m[s.Substring(i, 1)]++; } // printing all distinct palindromes from // hash map Console.WriteLine( "Below are " + (m.Count)); foreach (KeyValuePair < string , int > ii in m) Console.WriteLine(ii.Key); } // Driver Code public static void Main( string [] args) { palindromeSubStrs( "abaaa" ); } } // This code is contributed by // sanjeev2552 |
Javascript
<script> // JavaScript program to find all distinct palindrome sub-strings // of a given string // Function to print all distinct palindrome sub-strings of s function palindromeSubStrs(s) { let m = new Map(); let n = s.length; // table for storing results (2 rows for odd- // and even-length palindromes let R = new Array(2); for (let i = 0; i < 2; i++) R[i] = new Array(n + 1); // Find all sub-string palindromes from the given input // string insert 'guards' to iterate easily over s s = "@" + s + "#" ; for (let j = 0; j <= 1; j++) { let rp = 0; // length of 'palindrome radius' R[j][0] = 0; let i = 1; while (i <= n) { // Attempt to expand palindrome centered at i while (s[i - rp - 1] == s[i + j + rp]) rp++; // Incrementing the length of palindromic // radius as and when we find valid palindrome // Assigning the found palindromic length to odd/even // length array R[j][i] = rp; let k = 1; while ((R[j][i - k] != rp - k) && (k < rp)) { R[j][i + k] = Math.min(R[j][i - k],rp - k); k++; } rp = Math.max(rp - k,0); i += k; } } // remove 'guards' s = s.substring(1, n+1); // Put all obtained palindromes in a hash map to // find only distinct palindromes m.set(`${s[0]}`,1); for (let i = 1; i < n; i++) { for (let j = 0; j <= 1; j++){ for (let rp = R[j][i]; rp > 0; rp--){ m.set(s.substring(i - rp - 1, i + rp + j-1),1); } } m.set(`${s[i]}`,1); } // printing all distinct palindromes from hash map document.write(`Below are ${m.size} palindrome sub-strings`, "</br>" ); for (let [x, y] of m) document.write(x, "</br>" ); } // Driver program palindromeSubStrs( "abaaa" ); // This code is contributed by shinjanpatra </script> |
Output:
Below are 5 palindrome sub-strings a aa aaa aba b
Method 2 :
String length – N
Step 1 : Find all the palindromic sub-strings
First for every sub-string check if it is palindrome or not using dynamic programming like this – https://www.geeksforgeeks.org/count-palindrome-sub-strings-string/
Time complexity – O(N2) and Space complexity – O(N2)
Step 2 : Remove duplicate palindromes
For every index starting from index 0 we will use KMP algorithm and check if prefix and suffix is same and is palindrome then we will put 0 the dp array for that suffix sub-string
Time complexity O(N2) and Space complexity O(N) for KMP array
Step 3 : Print the distinct palindromes and number of such palindromes
For every sub-string check if it is present in dp array (i.e dp[i][j] == true) and print it.
Time complexity O(N2) and Space complexity O(N)
Overall Time complexity – O(N2)
Overall Space complexity – O(N2)
Below is the implementation of the above idea.
C++
// C++ program to find all distinct palindrome sub-strings // of a given string #include <iostream> #include <vector> using namespace std; int solve(string s) { int n = s.size(); // dp array to store whether a substring is palindrome // or not using dynamic programming we can solve this // in O(N^2) // dp[i][j] will be true (1) if substring (i, j) is // palindrome else false (0) 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 && s[i] == s[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 (s[i] == s[i + (len - 1)] && dp[i + 1][i + (len - 1) - 1]) { dp[i][i + (len - 1)] = true ; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* // here we will apply kmp algorithm for substrings // starting from i = 0 to n-1 when we will find prefix // and suffix of a substring to be equal and it is // palindrome we will make dp[i][j] for that suffix to be // false which means it is already added in the prefix // and we should not count it anymore. 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 (s[j + i] == s[k + i]) { // make suffix to be false // if this suffix is palindrome then it is // already 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; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* int count = 0; for ( int i = 0; i < n; i++) { string str; for ( int j = i; j < n; j++) { str += s[j]; if (dp[i][j]) { // count number of resultant distinct // substrings and print that substring count++; cout << str << '\n' ; } } } cout << "Total number of distinct palindromes is " << count << '\n' ; return 0; } // Driver code starts // This code is contributed by Aditya Anand int main() { string s1 = "abaaa" , s2 = "aaaaaaaaaa" ; solve(s1); solve(s2); return 0; } // Driver code ends |
Java
// Java program to find all distinct palindrome sub-strings // of a given string import java.util.*; class GFG { // Driver code starts public static void main(String[] args) { String s1 = "abaaa" , s2 = "aaaaaaaaaa" ; solve(s1); solve(s2); } public static int solve(String s) { int n = s.length(); // dp array to store whether a substring is // palindrome or not using dynamic programming we // can solve this in O(N^2) dp[i][j] will be true // (1) if substring (i, j) is palindrome else false // (0) boolean [][] dp = new boolean [n][n]; for ( int i = 0 ; i < n; i++) { // base case every char is palindrome dp[i][i] = true ; // check for every substring of length 2 if (i < n - 1 && s.charAt(i) == s.charAt(i + 1 )) { dp[i][i + 1 ] = true ; } } // 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 (s.charAt(i) == s.charAt(i + (len - 1 )) && dp[i + 1 ][i + (len - 1 ) - 1 ]) { dp[i][i + (len - 1 )] = true ; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* // here we will apply kmp algorithm for substrings // starting from i = 0 to n-1 when we will find // prefix and suffix of a substring to be equal and // it is palindrome we will make dp[i][j] for that // suffix to be false which means it is already // added in the prefix and we should not count it // anymore. int [] kmp = new int [n]; 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 (s.charAt(j + i) == s.charAt(k + i)) { // make suffix to be false // if this suffix is palindrome then it // is already 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 ; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* int count = 0 ; for ( int i = 0 ; i < n; i++) { String str = "" ; for ( int j = i; j < n; j++) { str += s.charAt(j); if (dp[i][j]) { // count number of resultant distinct // substrings and print that substring count++; System.out.println(str); } } } System.out.println( "Total number of distinct palindromes is " + count); return 0 ; } } // This code is contributed by kdheeraj. |
Python3
# Python3 program to find all distinct palindrome sub-strings # of a given string def solve(s): n = len (s) # dp array to store whether a substring is palindrome # or not using dynamic programming we can solve this # in O(N^2) # dp[i][j] will be true (1) if substring (i, j) is # palindrome else false (0) dp = [[ False for j in range (n)] for i in range (n)] for i in range (n): # base case every char is palindrome dp[i][i] = True # check for every substring of length 2 if i < n - 1 and s[i] = = s[i + 1 ]: dp[i][i + 1 ] = True # check every substring of length greater than 2 for # palindrome for lenk in range ( 3 , n + 1 ): for i in range (n - lenk + 1 ): if s[i] = = s[i + lenk - 1 ] and dp[i + 1 ][i + lenk - 2 ]: dp[i][i + lenk - 1 ] = True # here we will apply kmp algorithm for substrings # starting from i = 0 to n-1 when we will find prefix # and suffix of a substring to be equal and it is # palindrome we will make dp[i][j] for that suffix to be # false which means it is already added in the prefix # and we should not count it anymore. kmp = [ 0 ] * n for i in range (n): # starting kmp for every i from 0 to n-1 j, k = 0 , 1 while k + i < n: if s[j + i] = = s[k + i]: # make suffix to be false # if this suffix is palindrome then it is # already included in prefix dp[k + i - j][k + i] = False kmp[k] = j + 1 k + = 1 j + = 1 elif j > 0 : j = kmp[j - 1 ] else : kmp[k] = 0 k + = 1 count = 0 for i in range (n): str = "" for j in range (i, n): str + = s[j] if dp[i][j]: # count number of resultant distinct # substrings and print that substring count + = 1 print ( str ) print ( "Total number of distinct palindromes is" , count) return 0 # Driver code starts if __name__ = = "__main__" : s1 = "abaaa" s2 = "aaaaaaaaaa" solve(s1) solve(s2) # This code is contributed by lokeshpotta20. |
Javascript
// Javascript program to find all distinct palindrome sub-strings // of a given string function solve(s) { let n = s.length; // dp array to store whether a substring is palindrome // or not using dynamic programming we can solve this // in O(N^2) // dp[i][j] will be true (1) if substring (i, j) is // palindrome else false (0) let dp = new Array(n); for (let i = 0; i < n; i++) dp[i] = new Array(n).fill(0); for (let 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 && s[i] == s[i + 1]) { dp[i][i + 1] = 1; } } // check every substring of length greater than 2 for // palindrome for (let len = 3; len <= n; len++) { for (let i = 0; i + len - 1 < n; i++) { if (s[i] == s[i + (len - 1)] && dp[i + 1][i + (len - 1) - 1]) { dp[i][i + (len - 1)] = true ; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* // here we will apply kmp algorithm for substrings // starting from i = 0 to n-1 when we will find prefix // and suffix of a substring to be equal and it is // palindrome we will make dp[i][j] for that suffix to be // false which means it is already added in the prefix // and we should not count it anymore. let kmp= new Array(n).fill(0); for (let i = 0; i < n; i++) { // starting kmp for every i from 0 to n-1 let j = 0, k = 1; while (k + i < n) { if (s[j + i] == s[k + i]) { // make suffix to be false // if this suffix is palindrome then it is // already 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; } } } //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* let count = 0; for (let i = 0; i < n; i++) { let str= "" ; for (let j = i; j < n; j++) { str += s[j]; if (dp[i][j]) { // count number of resultant distinct // substrings and print that substring count++; console.log(str); } } } console.log( "Total number of distinct palindromes is " + count); } // Driver code starts let s1 = "abaaa" , s2 = "aaaaaaaaaa" ; solve(s1); solve(s2); // This code is contributed by ratiagrawal. |
a aba b aa aaa Total number of distinct palindromes is 5 a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaaaa Total number of distinct palindromes is 10
Similar Problem:
Count All Palindrome Sub-Strings in a String
This article is contributed by Vignesh Narayanan and Sowmya Sampath. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Please Login to comment...