Number of palindromic subsequences of length k where k<= 3
Last Updated :
25 Sep, 2023
Given a string S of length n and a positive integer k. The task is to find the number of Palindromic Subsequences of length k where k <= 3.
Examples:
Input : s = "aabab", k = 2
Output : 4
Input : s = "aaa", k = 3
Output : 1
Method 1:
For k = 1, we can easily say that number of characters in string will be the answer.
For k = 2, we can easily make pairs of same characters so we have to maintain the count of each character in string and then calculate
sum = 0
for character 'a' to 'z'
cnt = count(character)
sum = sum + cnt*(cnt-1)/2
sum is the answer.
Now as k increases, it became difficult to find. How to find the answer for k = 3 ? So the idea is to see that palindromes of length 3 will be of the format TZT, so we have to maintain two matrices, one to calculate the prefix sum of each character, and one to calculate suffix sum of each character in the string.
Prefix sum for a character T at index i is L[T][i] i.e number of times T has occurred in the range [0, i](indices).
Suffix sum for a character T at index i is R[T][i] has occurred in the range [i, n – 1](indices).
Both the matrices will be 26*n and one can precompute both these matrices in complexity O(26*n) where n is the length of the string.
Now how to compute the subsequence? Think over this:
for an index i suppose a character X appears n1 times in the range [0, i – 1] and n2 times in the range [i + 1, n – 1] then the answer for this character will be n1 * n2 i.e L[X][i-1] * R[X][i + 1], this will give the count of subsequences of the format X-s[i]-X where s[i] is the character at i-th index. So for every index i you will have to count the product of
L[X][i-1] * R[X][i+1],
where i is the range [1, n-2] and
X will be from 'a' to 'z'
Below is the implementation of this approach:
C++
#include <bits/stdc++.h>
#define MAX 100
#define MAX_CHAR 26
using namespace std;
void precompute(string s, int n, int l[][MAX],
int r[][MAX])
{
l[s[0] - 'a' ][0] = 1;
for ( int i = 1; i < n; i++) {
for ( int j = 0; j < MAX_CHAR; j++)
l[j][i] += l[j][i - 1];
l[s[i] - 'a' ][i]++;
}
r[s[n - 1] - 'a' ][n - 1] = 1;
for ( int i = n - 2; i >= 0; i--) {
for ( int j = 0; j < MAX_CHAR; j++)
r[j][i] += r[j][i + 1];
r[s[i] - 'a' ][i]++;
}
}
int countPalindromes( int k, int n, int l[][MAX],
int r[][MAX])
{
int ans = 0;
if (k == 1) {
for ( int i = 0; i < MAX_CHAR; i++)
ans += l[i][n - 1];
return ans;
}
if (k == 2) {
for ( int i = 0; i < MAX_CHAR; i++)
ans += ((l[i][n - 1] * (l[i][n - 1] - 1)) / 2);
return ans;
}
for ( int i = 1; i < n - 1; i++)
for ( int j = 0; j < MAX_CHAR; j++)
ans += l[j][i - 1] * r[j][i + 1];
return ans;
}
int main()
{
string s = "aabab" ;
int k = 2;
int n = s.length();
int l[MAX_CHAR][MAX] = { 0 }, r[MAX_CHAR][MAX] = { 0 };
precompute(s, n, l, r);
cout << countPalindromes(k, n, l, r) << endl;
return 0;
}
|
Java
import java.io.*;
class GFG {
static final int MAX = 100 ;
static final int MAX_CHAR = 26 ;
static void precompute(String s, int n, int l[][],
int r[][])
{
l[s.charAt( 0 ) - 'a' ][ 0 ] = 1 ;
for ( int i = 1 ; i < n; i++) {
for ( int j = 0 ; j < MAX_CHAR; j++)
l[j][i] += l[j][i - 1 ];
l[s.charAt(i) - 'a' ][i]++;
}
r[s.charAt(n - 1 ) - 'a' ][n - 1 ] = 1 ;
for ( int i = n - 2 ; i >= 0 ; i--) {
for ( int j = 0 ; j < MAX_CHAR; j++)
r[j][i] += r[j][i + 1 ];
r[s.charAt(i) - 'a' ][i]++;
}
}
static int countPalindromes( int k, int n, int l[][],
int r[][])
{
int ans = 0 ;
if (k == 1 ) {
for ( int i = 0 ; i < MAX_CHAR; i++)
ans += l[i][n - 1 ];
return ans;
}
if (k == 2 ) {
for ( int i = 0 ; i < MAX_CHAR; i++)
ans += ((l[i][n - 1 ] * (l[i][n - 1 ] - 1 ))
/ 2 );
return ans;
}
for ( int i = 1 ; i < n - 1 ; i++)
for ( int j = 0 ; j < MAX_CHAR; j++)
ans += l[j][i - 1 ] * r[j][i + 1 ];
return ans;
}
public static void main(String[] args)
{
String s = "aabab" ;
int k = 2 ;
int n = s.length();
int l[][] = new int [MAX_CHAR][MAX];
int r[][] = new int [MAX_CHAR][MAX];
precompute(s, n, l, r);
System.out.println(countPalindromes(k, n, l, r));
}
}
|
Python3
MAX = 100
MAX_CHAR = 26
def precompute(s, n, l, r):
l[ ord (s[ 0 ]) - ord ( 'a' )][ 0 ] = 1
for i in range ( 1 , n):
for j in range (MAX_CHAR):
l[j][i] + = l[j][i - 1 ]
l[ ord (s[i]) - ord ( 'a' )][i] + = 1
r[ ord (s[n - 1 ]) - ord ( 'a' )][n - 1 ] = 1
k = n - 2
while (k > = 0 ):
for j in range (MAX_CHAR):
r[j][k] + = r[j][k + 1 ]
r[ ord (s[k]) - ord ( 'a' )][k] + = 1
k - = 1
def countPalindromes(k, n, l, r):
ans = 0
if (k = = 1 ):
for i in range (MAX_CHAR):
ans + = l[i][n - 1 ]
return ans
if (k = = 2 ):
for i in range (MAX_CHAR):
ans + = ((l[i][n - 1 ] * (l[i][n - 1 ] - 1 )) / 2 )
return ans
for i in range ( 1 , n - 1 ):
for j in range (MAX_CHAR):
ans + = l[j][i - 1 ] * r[j][i + 1 ]
return ans
s = "aabab"
k = 2
n = len (s)
l = [[ 0 for x in range ( MAX )] for y in range (MAX_CHAR)]
r = [[ 0 for x in range ( MAX )] for y in range (MAX_CHAR)]
precompute(s, n, l, r)
print (countPalindromes(k, n, l, r))
|
C#
using System;
class GFG {
static int MAX=100;
static int MAX_CHAR=26;
static void precompute( string s, int n,
int [,]l, int [,]r)
{
l[s[0] - 'a' ,0] = 1;
for ( int i = 1; i < n; i++)
{
for ( int j = 0; j < MAX_CHAR; j++)
l[j, i] += l[j,i - 1];
l[s[i] - 'a' ,i]++;
}
r[s[n - 1] - 'a' ,n - 1] = 1;
for ( int i = n - 2; i >= 0; i--)
{
for ( int j = 0; j < MAX_CHAR; j++)
r[j, i] += r[j,i + 1];
r[s[i] - 'a' ,i]++;
}
}
static int countPalindromes( int k, int n,
int [,]l, int [,]r)
{
int ans = 0;
if (k == 1)
{
for ( int i = 0; i < MAX_CHAR; i++)
ans += l[i,n - 1];
return ans;
}
if (k == 2) {
for ( int i = 0; i < MAX_CHAR; i++)
ans += ((l[i,n - 1] *
(l[i,n - 1] - 1)) / 2);
return ans;
}
for ( int i = 1; i < n - 1; i++)
for ( int j = 0; j < MAX_CHAR; j++)
ans += l[j,i - 1] * r[j, i + 1];
return ans;
}
public static void Main ()
{
string s = "aabab" ;
int k = 2;
int n = s.Length;
int [,]l= new int [MAX_CHAR,MAX];
int [,]r= new int [MAX_CHAR,MAX];
precompute(s, n, l, r);
Console.Write(countPalindromes(k, n, l, r));
}
}
|
Javascript
<script>
let MAX=100;
let MAX_CHAR=26;
function precompute(s,n,l,r)
{
l[s[0].charCodeAt(0) - 'a' .charCodeAt(0)][0] = 1;
for (let i = 1; i < n; i++) {
for (let j = 0; j < MAX_CHAR; j++)
l[j][i] += l[j][i - 1];
l[s[i].charCodeAt(0) - 'a' .charCodeAt(0)][i]++;
}
r[s[n-1].charCodeAt(0) - 'a' .charCodeAt(0)][n - 1] = 1;
for (let i = n - 2; i >= 0; i--) {
for (let j = 0; j < MAX_CHAR; j++)
r[j][i] += r[j][i + 1];
r[s[i].charCodeAt(0) - 'a' .charCodeAt(0)][i]++;
}
}
function countPalindromes(k,n,l,r)
{
let ans = 0;
if (k == 1) {
for (let i = 0; i < MAX_CHAR; i++)
ans += l[i][n - 1];
return ans;
}
if (k == 2) {
for (let i = 0; i < MAX_CHAR; i++)
ans += ((l[i][n - 1] * (l[i][n - 1] - 1)) / 2);
return ans;
}
for (let i = 1; i < n - 1; i++)
for (let j = 0; j < MAX_CHAR; j++)
ans += l[j][i - 1] * r[j][i + 1];
return ans;
}
let s = "aabab" ;
let k = 2;
let n = s.length;
let l= new Array(MAX_CHAR);
let r= new Array(MAX_CHAR);
for (let i=0;i<MAX_CHAR;i++)
{
l[i]= new Array(MAX);
r[i]= new Array(MAX);
for (let j=0;j<MAX;j++)
{
l[i][j]=0;
r[i][j]=0;
}
}
precompute(s, n, l, r);
document.write(countPalindromes(k, n, l, r));
</script>
|
PHP
<?php
$MAX = 100;
$MAX_CHAR = 26;
function precompute( $s , $n , & $l , & $r )
{
global $MAX , $MAX_CHAR ;
$l [ord( $s [0]) - ord( 'a' )][0] = 1;
for ( $i = 1; $i < $n ; $i ++)
{
for ( $j = 0; $j < $MAX_CHAR ; $j ++)
$l [ $j ][ $i ] += $l [ $j ][ $i - 1];
$l [ord( $s [ $i ]) - ord( 'a' )][ $i ]++;
}
$r [ord( $s [ $n - 1]) - ord( 'a' )][ $n - 1] = 1;
for ( $i = $n - 2; $i >= 0; $i --)
{
for ( $j = 0; $j < $MAX_CHAR ; $j ++)
$r [ $j ][ $i ] += $r [ $j ][ $i + 1];
$r [ord( $s [ $i ]) - ord( 'a' )][ $i ]++;
}
}
function countPalindromes( $k , $n , & $l , & $r )
{
global $MAX , $MAX_CHAR ;
$ans = 0;
if ( $k == 1)
{
for ( $i = 0; $i < $MAX_CHAR ; $i ++)
$ans += $l [ $i ][ $n - 1];
return $ans ;
}
if ( $k == 2)
{
for ( $i = 0; $i < $MAX_CHAR ; $i ++)
$ans += (( $l [ $i ][ $n - 1] *
( $l [ $i ][ $n - 1] - 1)) / 2);
return $ans ;
}
for ( $i = 1; $i < $n - 1; $i ++)
for ( $j = 0; $j < $MAX_CHAR ; $j ++)
$ans += $l [ $j ][ $i - 1] *
$r [ $j ][ $i + 1];
return $ans ;
}
$s = "aabab" ;
$k = 2;
$n = strlen ( $s );
$l = array_fill (0, $MAX_CHAR ,
array_fill (0, $MAX , NULL));
$r = array_fill (0, $MAX_CHAR ,
array_fill (0, $MAX , NULL));
precompute( $s , $n , $l , $r );
echo countPalindromes( $k , $n , $l , $r ) . "\n" ;
?>
|
Time Complexity: O(26*n)
Auxiliary Space: O(26 * MAX), where MAX = 100
Approach#2: Using combinations
The approach uses the approach of generating all possible combinations of length ‘k’ from the given string and checking if each combination is a palindrome.
Algorithm
1. Initialize a counter variable ‘count’ to 0.
2. Generate all possible combinations of length ‘k’ from the given string.
3. Check if each combination is a palindrome or not.
4. If a combination is a palindrome, increment ‘count’ by 1.
5. Return ‘count’ as the number of palindromic subsequences of length ‘k’.
C++
#include <bits/stdc++.h>
using namespace std;
void generateCombinations( char s[], string sb, int index,
int k,
vector<string>& combinations)
{
if (sb.length() == k) {
combinations.push_back(sb);
return ;
}
for ( int i = index; i < strlen (s); i++) {
sb.push_back(s[i]);
generateCombinations(s, sb, i + 1, k, combinations);
sb.pop_back();
}
}
bool isPalindrome(string sub)
{
return sub == string(sub.rbegin(), sub.rend());
}
int palindromicSubsequences(string s, int k)
{
int count = 0;
vector<string> combinations;
generateCombinations(&s[0], "" , 0, k, combinations);
for (string sub : combinations) {
if (isPalindrome(sub)) {
count++;
}
}
return count;
}
int main()
{
string s = "aabab" ;
int k = 2;
cout << palindromicSubsequences(s, k);
}
|
Java
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args)
{
String s = "aabab" ;
int k = 2 ;
System.out.println(palindromicSubsequences(s, k));
}
public static int palindromicSubsequences(String s,
int k)
{
int count = 0 ;
List<String> combinations = new ArrayList<>();
generateCombinations(s.toCharArray(),
new StringBuilder(), 0 , k,
combinations);
for (String sub : combinations) {
if (isPalindrome(sub)) {
count++;
}
}
return count;
}
public static void
generateCombinations( char [] s, StringBuilder sb,
int index, int k,
List<String> combinations)
{
if (sb.length() == k) {
combinations.add(sb.toString());
return ;
}
for ( int i = index; i < s.length; i++) {
sb.append(s[i]);
generateCombinations(s, sb, i + 1 , k,
combinations);
sb.deleteCharAt(sb.length() - 1 );
}
}
public static boolean isPalindrome(String sub)
{
return sub.equals(
new StringBuilder(sub).reverse().toString());
}
}
|
Python3
def is_palindrome(sub):
return sub = = sub[:: - 1 ]
def palindromic_subsequences(s, k):
count = 0
from itertools import combinations
for sub in combinations(s, k):
if is_palindrome(''.join(sub)):
count + = 1
return count
s = "aabab"
k = 2
print (palindromic_subsequences(s, k))
|
C#
using System;
using System.Collections.Generic;
class Program
{
static void GenerateCombinations( char [] s, string sb, int index, int k, List< string > combinations)
{
if (sb.Length == k)
{
combinations.Add(sb);
return ;
}
for ( int i = index; i < s.Length; i++)
{
sb += s[i];
GenerateCombinations(s, sb, i + 1, k, combinations);
sb = sb.Remove(sb.Length - 1);
}
}
static bool IsPalindrome( string sub)
{
char [] charArray = sub.ToCharArray();
Array.Reverse(charArray);
return sub == new string (charArray);
}
static int PalindromicSubsequences( string s, int k)
{
int count = 0;
List< string > combinations = new List< string >();
GenerateCombinations(s.ToCharArray(), "" , 0, k, combinations);
foreach ( string sub in combinations)
{
if (IsPalindrome(sub))
{
count++;
}
}
return count;
}
static void Main( string [] args)
{
string s = "aabab" ;
int k = 2;
Console.WriteLine(PalindromicSubsequences(s, k));
}
}
|
Javascript
function is_palindrome(sub) {
return sub === sub.split( '' ).reverse().join( '' );
}
function palindromic_subsequences(s, k) {
let count = 0;
let combinations = getCombinations(s.split( '' ), k);
for (let sub of combinations) {
if (is_palindrome(sub.join( '' ))) {
count += 1;
}
}
return count;
}
function getCombinations(arr, k) {
let i, j, combs, head, tailcombs;
if (k > arr.length || k <= 0) {
return [];
}
if (k === arr.length) {
return [arr];
}
if (k === 1) {
combs = [];
for (i = 0; i < arr.length; i++) {
combs.push([arr[i]]);
}
return combs;
}
combs = [];
for (i = 0; i < arr.length - k + 1; i++) {
head = arr.slice(i, i + 1);
tailcombs = getCombinations(arr.slice(i + 1), k - 1);
for (j = 0; j < tailcombs.length; j++) {
combs.push(head.concat(tailcombs[j]));
}
}
return combs;
}
let s = "aabab" ;
let k = 2;
console.log(palindromic_subsequences(s, k));
|
Time Complexity: O(n^k * k) – Generating all possible combinations of length ‘k’ takes O(n^k) time, and checking if each combination is a palindrome takes O(k) time.
Space Complexity: O(n) – The space used by the program is dominated by the length of the input string.
Share your thoughts in the comments
Please Login to comment...