Given a string s of length n, count the number of substrings having different types of palindromic characteristics.
Palindromic Characteristic is the number of k-palindromes in a string where k lies in range [0, n).
A string is 1-palindrome(or simply palindrome) if and only if it reads the same backward as it reads forward.
A string is k-palindrome (k > 1) if and only if :
- Its left half is equal to its right half.
- Its left half and right half should be non-empty (k - 1)-palindrome. The left half of a string of length 't' is its prefix of length ?t/2?, and the right half is the suffix of the same length.
Note: Each substring is counted as many times as it appears in the string. For example, in the string "aaa" the substring "a" appears 3 times.
Examples :
Input : abba Output : 6 1 0 0 Explanation : "6" 1-palindromes = "a", "b", "b", "a", "bb", "abba". "1" 2-palindrome = "bb". Because "b" is 1-palindrome and "bb" has both left and right parts equal. "0" 3-palindrome and 4-palindrome. Input : abacaba Output : 12 4 1 0 0 0 0 Explanation : "12" 1-palindromes = "a", "b", "a", "c", "a", "b", "a", "aba", "aca", "aba", "bacab", "abacaba". "4" 2-palindromes = "aba", "aca", "aba", "abacaba". Because "a" and "aba" are 1-palindromes. NOTE : "bacab" is not 2-palindrome as "ba" is not 1-palindrome. "1" 3-palindrome = "abacaba". Because is "aba" is 2-palindrome. "0" other k-palindromes where 4 < = k < = 7.
Approach:
Take a string s and say it is a 1-palindrome and checking its left half also turns out to be a 1-palindrome then, obviously its right part will always be equal to the left part (as the string is also a 1-palindrome) making the original string to be 2-palindrome.
Now, similarly, checking the left half of the string, it also turns out to be a 1-palindrome then it will make the left half to be 2-palindrome and hence, making the original string to be 3-palindrome and so on checking it till only 1 alphabet is left or the part is not a 1-palindrome.
Let's take string = "abacaba". As known "abacaba" is 1-palindrome. So, when checking for its left half "aba", which is also a 1-palindrome, it makes "abacaba" a 2-palindrome. Then, check for "aba"'s left half "a" which is also a 1-palindrome. So it makes "aba" a 2-palindrome and "aba" makes "abacaba" a 3-palindrome. So in other words, if a string is a k-palindrome then it is also a (k-1)-palindrome, (k-2)-palindrome, and so on till 1-palindrome. Code for the same is given below which firsts check each and every substring if it is a palindrome or not and then counts the number of k-palindromic substrings recursively in logarithmic time.
Below is the implementation of above approach :
// A C++ program which counts different
// palindromic characteristics of a string.
#include <bits/stdc++.h>
using namespace std;
const int MAX_STR_LEN = 1000;
bool P[MAX_STR_LEN][MAX_STR_LEN];
int Kpal[MAX_STR_LEN];
// A C++ function which checks whether a
// substring str[i..j] of a given string
// is a palindrome or not.
void checkSubStrPal(string str, int n)
{
// P[i][j] = true if substring str
// [i..j] is palindrome, else false
memset(P, false, sizeof(P));
// palindrome of single length
for (int i = 0; i < n; i++)
P[i][i] = true;
// palindrome of length 2
for (int i = 0; i < n - 1; i++)
if (str[i] == str[i + 1])
P[i][i + 1] = true;
// Palindromes of length more than 2.
// This loop is similar to Matrix Chain
// Multiplication. We start with a gap of
// length 2 and fill P table in a way that
// gap between starting and ending indexes
// increases one by one by outer loop.
for (int gap = 2; gap < n; gap++)
{
// Pick starting point for current gap
for (int i = 0; i < n - gap; i++)
{
// Set ending point
int j = gap + i;
// If current string is palindrome
if (str[i] == str[j] && P[i + 1][j - 1])
P[i][j] = true;
}
}
}
// A C++ function which recursively
// counts if a string str [i..j] is
// a k-palindromic string or not.
void countKPalindromes(int i, int j, int k)
{
// terminating condition for a
// string which is a k-palindrome.
if (i == j)
{
Kpal[k]++;
return;
}
// terminating condition for a
// string which is not a k-palindrome.
if (P[i][j] == false)
return;
// increases the counter for the
// string if it is a k-palindrome.
Kpal[k]++;
// mid is middle pointer of
// the string str [i...j].
int mid = (i + j) / 2;
// if length of string which is
// (j - i + 1) is odd than we have
// to subtract one from mid.
// else if even then no change.
if ((j - i + 1) % 2 == 1)
mid--;
// if the string is k-palindrome
// then we check if it is a
// (k+1) - palindrome or not by
// just sending any of one half of
// the string to the Count_k_Palindrome
// function.
countKPalindromes(i, mid, k + 1);
}
void printKPalindromes(string s)
{
// Count of k-palindromes is equal
// to zero initially.
memset(Kpal, 0, sizeof(Kpal));
// Finding all palindromic
// substrings of given string
int n = s.length();
checkSubStrPal(s, n);
// counting k-palindromes for each and
// every substring of given string. .
for (int i = 0; i < n; i++)
for (int j = 0; j < n - i; j++)
countKPalindromes(j, j + i, 1);
// Output the number of K-palindromic
// substrings of a given string.
for (int i = 1; i <= n; i++)
cout << Kpal[i] << " ";
cout << "\n";
}
// Driver code
int main()
{
string s = "abacaba";
printKPalindromes(s);
return 0;
}
// Java program which counts
// different palindromic
// characteristics of a string.
import java.io.*;
class GFG
{
static int MAX_STR_LEN = 1000;
static boolean P[][] =
new boolean[MAX_STR_LEN][MAX_STR_LEN];
static int []Kpal =
new int[MAX_STR_LEN];
// function which checks
// whether a substring
// str[i..j] of a given
// string is a palindrome or not.
static void checkSubStrPal(String str,
int n)
{
// P[i,j] = true if substring
// str [i..j] is palindrome,
// else false
for (int i = 0; i < MAX_STR_LEN; i++)
{
for (int j = 0; j < MAX_STR_LEN; j++)
P[i][j] = false;
Kpal[i] = 0;
}
// palindrome of
// single length
for (int i = 0; i < n; i++)
P[i][i] = true;
// palindrome of
// length 2
for (int i = 0; i < n - 1; i++)
if (str.charAt(i) == str.charAt(i + 1))
P[i][i + 1] = true;
// Palindromes of length
// more than 2. This loop
// is similar to Matrix
// Chain Multiplication.
// We start with a gap of
// length 2 and fill P table
// in a way that gap between
// starting and ending indexes
// increases one by one by
// outer loop.
for (int gap = 2; gap < n; gap++)
{
// Pick starting point
// for current gap
for (int i = 0; i < n - gap; i++)
{
// Set ending point
int j = gap + i;
// If current string
// is palindrome
if (str.charAt(i) == str.charAt(j) &&
P[i + 1][j - 1])
P[i][j] = true;
}
}
}
// A function which recursively
// counts if a string str [i..j] is
// a k-palindromic string or not.
static void countKPalindromes(int i, int j,
int k)
{
// terminating condition
// for a string which is
// a k-palindrome.
if (i == j)
{
Kpal[k]++;
return;
}
// terminating condition for
// a string which is not a
// k-palindrome.
if (P[i][j] == false)
return;
// increases the counter
// for the string if it
// is a k-palindrome.
Kpal[k]++;
// mid is middle pointer of
// the string str [i...j].
int mid = (i + j) / 2;
// if length of string which
// is (j - i + 1) is odd than
// we have to subtract one
// from mid else if even then
// no change.
if ((j - i + 1) % 2 == 1)
mid--;
// if the string is k-palindrome
// then we check if it is a
// (k+1) - palindrome or not
// by just sending any of one
// half of the string to the
// Count_k_Palindrome function.
countKPalindromes(i, mid, k + 1);
}
static void printKPalindromes(String s)
{
// Finding all palindromic
// substrings of given string
int n = s.length();
checkSubStrPal(s, n);
// counting k-palindromes for
// each and every substring
// of given string. .
for (int i = 0; i < n; i++)
for (int j = 0; j < n - i; j++)
countKPalindromes(j, j + i, 1);
// Output the number of
// K-palindromic substrings
// of a given string.
for (int i = 1; i <= n; i++)
System.out.print(Kpal[i] + " ");
System.out.println();
}
// Driver code
public static void main(String args[])
{
String s = "abacaba";
printKPalindromes(s);
}
}
// This code is contributed by
// Manish Shaw(manishshaw1)
# Python program which counts
# different palindromic
# characteristics of a string.
MAX_STR_LEN = 1000;
P = [[0 for x in range(MAX_STR_LEN)]
for y in range(MAX_STR_LEN)] ;
for i in range(0, MAX_STR_LEN) :
for j in range(0, MAX_STR_LEN) :
P[i][j] = False;
Kpal = [0] * MAX_STR_LEN;
# def which checks
# whether a substr[i..j]
# of a given is a
# palindrome or not.
def checkSubStrPal(str, n) :
global P, Kpal, MAX_STR_LEN;
# P[i,j] = True if substr
# [i..j] is palindrome,
# else False
for i in range(0, MAX_STR_LEN) :
for j in range(0, MAX_STR_LEN) :
P[i][j] = False;
Kpal[i] = 0;
# palindrome of
# single length
for i in range(0, n) :
P[i][i] = True;
# palindrome of
# length 2
for i in range(0, n - 1) :
if (str[i] == str[i + 1]) :
P[i][i + 1] = True;
# Palindromes of length more
# than 2. This loop is similar
# to Matrix Chain Multiplication.
# We start with a gap of length
# 2 and fill P table in a way
# that gap between starting and
# ending indexes increases one
# by one by outer loop.
for gap in range(2, n) :
# Pick starting point
# for current gap
for i in range(0, n - gap) :
# Set ending point
j = gap + i;
# If current string
# is palindrome
if (str[i] == str[j] and
P[i + 1][j - 1]) :
P[i][j] = True;
# A Python def which
# recursively counts if
# a str [i..j] is a
# k-palindromic or not.
def countKPalindromes(i, j, k) :
global Kpal, P;
# terminating condition
# for a which is a
# k-palindrome.
if (i == j) :
Kpal[k] = Kpal[k] + 1;
return;
# terminating condition
# for a which is not a
# k-palindrome.
if (P[i][j] == False) :
return;
# increases the counter
# for the if it is a
# k-palindrome.
Kpal[k] = Kpal[k] + 1;
# mid is middle pointer
# of the str [i...j].
mid = int((i + j) / 2);
# if length of which is
# (j - i + 1) is odd than
# we have to subtract one
# from mid else if even
# then no change.
if ((j - i + 1) % 2 == 1) :
mid = mid - 1;
# if the is k-palindrome
# then we check if it is a
# (k+1) - palindrome or not
# by just sending any of
# one half of the to the
# Count_k_Palindrome def.
countKPalindromes(i, mid, k + 1);
def printKPalindromes(s) :
global P, Kpal, MAX_STR_LEN;
# Finding all palindromic
# substrings of given string
n = len(s);
checkSubStrPal(s, n);
# counting k-palindromes
# for each and every sub
# of given string. .
for i in range(0, n) :
for j in range(0, n - i) :
countKPalindromes(j, j + i, 1);
# Output the number of
# K-palindromic substrings
# of a given string.
for i in range(1, n + 1) :
print (Kpal[i], end=" ");
print();
# Driver code
s = "abacaba";
printKPalindromes(s);
# This code is contributed by
# Manish Shaw(manishshaw1)
// C# program which counts
// different palindromic
// characteristics of a string.
using System;
class GFG
{
static int MAX_STR_LEN = 1000;
static bool [,]P = new bool[MAX_STR_LEN,
MAX_STR_LEN];
static int []Kpal = new int[MAX_STR_LEN];
// function which checks whether
// a substring str[i..j] of a
// given string is a palindrome or not.
static void checkSubStrPal(string str,
int n)
{
// P[i,j] = true if substring str
// [i..j] is palindrome, else false
for (int i = 0; i < MAX_STR_LEN; i++)
{
for (int j = 0; j < MAX_STR_LEN; j++)
P[i, j] = false;
Kpal[i] = 0;
}
// palindrome of single length
for (int i = 0; i < n; i++)
P[i, i] = true;
// palindrome of length 2
for (int i = 0; i < n - 1; i++)
if (str[i] == str[i + 1])
P[i, i + 1] = true;
// Palindromes of length more
// than 2. This loop is similar
// to Matrix Chain Multiplication.
// We start with a gap of length 2
// and fill P table in a way that
// gap between starting and ending
// indexes increases one by one by
// outer loop.
for (int gap = 2; gap < n; gap++)
{
// Pick starting point
// for current gap
for (int i = 0; i < n - gap; i++)
{
// Set ending point
int j = gap + i;
// If current string
// is palindrome
if (str[i] == str[j] &&
P[i + 1, j - 1])
P[i, j] = true;
}
}
}
// A C++ function which recursively
// counts if a string str [i..j] is
// a k-palindromic string or not.
static void countKPalindromes(int i, int j,
int k)
{
// terminating condition for a
// string which is a k-palindrome.
if (i == j)
{
Kpal[k]++;
return;
}
// terminating condition for
// a string which is not a
// k-palindrome.
if (P[i, j] == false)
return;
// increases the counter for the
// string if it is a k-palindrome.
Kpal[k]++;
// mid is middle pointer of
// the string str [i...j].
int mid = (i + j) / 2;
// if length of string which is
// (j - i + 1) is odd than we have
// to subtract one from mid.
// else if even then no change.
if ((j - i + 1) % 2 == 1)
mid--;
// if the string is k-palindrome
// then we check if it is a
// (k+1) - palindrome or not
// by just sending any of one
// half of the string to the
// Count_k_Palindrome function.
countKPalindromes(i, mid, k + 1);
}
static void printKPalindromes(string s)
{
// Finding all palindromic
// substrings of given string
int n = s.Length;
checkSubStrPal(s, n);
// counting k-palindromes for each and
// every substring of given string. .
for (int i = 0; i < n; i++)
for (int j = 0; j < n - i; j++)
countKPalindromes(j, j + i, 1);
// Output the number of K-palindromic
// substrings of a given string.
for (int i = 1; i <= n; i++)
Console.Write(Kpal[i] + " ");
Console.WriteLine();
}
// Driver code
static void Main()
{
string s = "abacaba";
printKPalindromes(s);
}
}
// This code is contributed by
// Manish Shaw(manishshaw1)
<?php
// PHP program which counts
// different palindromic
// characteristics of a string.
$MAX_STR_LEN = 1000;
$P = array(array());
$Kpal = array_fill(0, $MAX_STR_LEN, 0);
for($i = 0; $i < $MAX_STR_LEN; $i++)
{
for($j = 0; $j < $MAX_STR_LEN; $j++)
$P[$i][$j] = false;
}
// function which checks
// whether a substr[i..j]
// of a given is a
// palindrome or not.
function checkSubStrPal($str,
$n)
{
global $P, $Kpal,
$MAX_STR_LEN;
// P[i,j] = true if substr
// [i..j] is palindrome, else false
for ($i = 0;
$i < $MAX_STR_LEN; $i++)
{
for ($j = 0;
$j < $MAX_STR_LEN; $j++)
$P[$i][$j] = false;
$Kpal[$i] = 0;
}
// palindrome of
// single length
for ($i = 0; $i < $n; $i++)
$P[$i][$i] = true;
// palindrome of
// length 2
for ($i = 0; $i < $n - 1; $i++)
if ($str[$i] == $str[$i + 1])
$P[$i][$i + 1] = true;
// Palindromes of length more
// than 2. This loop is similar
// to Matrix Chain Multiplication.
// We start with a gap of length
// 2 and fill P table in a way
// that gap between starting and
// ending indexes increases one
// by one by outer loop.
for ($gap = 2; $gap < $n; $gap++)
{
// Pick starting point
// for current gap
for ($i = 0;
$i < $n - $gap; $i++)
{
// Set ending point
$j = $gap + $i;
// If current string
// is palindrome
if ($str[$i] == $str[$j] &&
$P[$i + 1][$j - 1])
$P[$i][$j] = true;
}
}
}
// A PHP function which
// recursively counts if
// a str [i..j] is a
// k-palindromic or not.
function countKPalindromes($i, $j, $k)
{
global $Kpal, $P;
// terminating condition for a
// which is a k-palindrome.
if ($i == $j)
{
$Kpal[$k]++;
return;
}
// terminating condition
// for a which is not a
// k-palindrome.
if ($P[$i][$j] == false)
return;
// increases the counter
// for the if it is a
// k-palindrome.
$Kpal[$k]++;
// mid is middle pointer
// of the str [i...j].
$mid = ($i + $j) / 2;
// if length of which is
// (j - i + 1) is odd than
// we have to subtract one
// from mid else if even
// then no change.
if (($j - $i + 1) % 2 == 1)
$mid--;
// if the is k-palindrome
// then we check if it is a
// (k+1) - palindrome or not
// by just sending any of
// one half of the to the
// Count_k_Palindrome function.
countKPalindromes($i, $mid,
$k + 1);
}
function printKPalindromes($s)
{
global $P, $Kpal,
$MAX_STR_LEN;
// Finding all palindromic
// substrings of given string
$n = strlen($s);
checkSubStrPal($s, $n);
// counting k-palindromes
// for each and every sub
// of given string. .
for ($i = 0; $i < $n; $i++)
for ($j = 0; $j < $n - $i; $j++)
countKPalindromes($j, $j +
$i, 1);
// Output the number of
// K-palindromic substrings
// of a given string.
for ($i = 1; $i <= $n; $i++)
echo ($Kpal[$i] . " ");
echo("\n");
}
// Driver code
$s = "abacaba";
printKPalindromes($s);
// This code is contributed by
// Manish Shaw(manishshaw1)
?>
// A javascript program which counts different
// palindromic characteristics of a string.
let MAX_STR_LEN = 1000;
let P = new Array(MAX_STR_LEN);
for(let i = 0; i < MAX_STR_LEN; i++){
P[i] = new Array(MAX_STR_LEN);
}
let Kpal = new Array(MAX_STR_LEN);
// A JavaScript function which checks whether a
// substring str[i..j] of a given string
// is a palindrome or not.
function checkSubStrPal(str, n)
{
// P[i][j] = true if substring str
// [i..j] is palindrome, else false
for(let i = 0; i < P.length; i++){
for(let j = 0; j < P[0].length; j++){
P[i][j] = false;
}
}
// palindrome of single length
for (let i = 0; i < n; i++)
P[i][i] = true;
// palindrome of length 2
for (let i = 0; i < n - 1; i++)
if (str[i] == str[i + 1])
P[i][i + 1] = true;
// Palindromes of length more than 2.
// This loop is similar to Matrix Chain
// Multiplication. We start with a gap of
// length 2 and fill P table in a way that
// gap between starting and ending indexes
// increases one by one by outer loop.
for (let gap = 2; gap < n; gap++)
{
// Pick starting point for current gap
for (let i = 0; i < n - gap; i++)
{
// Set ending point
let j = gap + i;
// If current string is palindrome
if (str[i] == str[j] && P[i + 1][j - 1])
P[i][j] = true;
}
}
}
// A C++ function which recursively
// counts if a string str [i..j] is
// a k-palindromic string or not.
function countKPalindromes(i, j, k)
{
// terminating condition for a
// string which is a k-palindrome.
if (i == j)
{
Kpal[k] = Kpal[k] + 1;
return;
}
// terminating condition for a
// string which is not a k-palindrome.
if (P[i][j] == false)
return;
// increases the counter for the
// string if it is a k-palindrome.
Kpal[k] = Kpal[k] + 1;
// mid is middle pointer of
// the string str [i...j].
let mid = Math.floor((i + j) / 2);
// if length of string which is
// (j - i + 1) is odd than we have
// to subtract one from mid.
// else if even then no change.
if ((j - i + 1) % 2 == 1)
mid = mid - 1;
// if the string is k-palindrome
// then we check if it is a
// (k+1) - palindrome or not by
// just sending any of one half of
// the string to the Count_k_Palindrome
// function.
countKPalindromes(i, mid, k + 1);
}
function printKPalindromes(s)
{
// Count of k-palindromes is equal
// to zero initially.
for(let i = 0; i < Kpal.length; i++){
Kpal[i] = 0;
}
// Finding all palindromic
// substrings of given string
let n = s.length;
checkSubStrPal(s, n);
// counting k-palindromes for each and
// every substring of given string. .
for (let i = 0; i < n; i++)
for (let j = 0; j < n - i; j++)
countKPalindromes(j, j + i, 1);
// Output the number of K-palindromic
// substrings of a given string.
for (let i = 1; i <= n; i++)
console.log(Kpal[i] + " ");
}
// Driver code
let s = "abacaba";
printKPalindromes(s);
Output
12 4 1 0 0 0 0
Complexity Analysis:
- Time Complexity : O(
n^2$\log{n}$ ) - Auxiliary Space : O(
n^2 )