Open In App

Number of palindromic subsequences of length k where k<= 3

Improve
Improve
Like Article
Like
Save
Share
Report

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++




// CPP program to count number of subsequences of
// given length.
#include <bits/stdc++.h>
#define MAX 100
#define MAX_CHAR 26
using namespace std;
 
// Precompute the prefix and suffix array.
void precompute(string s, int n, int l[][MAX],
                                 int r[][MAX])
{
    l[s[0] - 'a'][0] = 1;
 
    // Precompute the prefix 2D array
    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;
 
    // Precompute the Suffix 2D array.
    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]++;
    }
}
 
// Find the number of palindromic subsequence of
// length k
int countPalindromes(int k, int n, int l[][MAX],
                                   int r[][MAX])
{
    int ans = 0;
 
    // If k is 1.
    if (k == 1) {
        for (int i = 0; i < MAX_CHAR; i++)
            ans += l[i][n - 1]; 
        return ans;
    }
 
    // If k is 2
    if (k == 2) {
 
        // Adding all the products of prefix array
        for (int i = 0; i < MAX_CHAR; i++)            
            ans += ((l[i][n - 1] * (l[i][n - 1] - 1)) / 2);
        return ans;
    }
 
    // For k greater than 2. Adding all the products
    // of value of prefix and suffix array.
    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;
}
 
// Driven Program
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




// Java program to count number of subsequences of
// given length.
import java.io.*;
class GFG {
 
    static final int MAX = 100;
    static final int MAX_CHAR = 26;
 
    // Precompute the prefix and suffix array.
    static void precompute(String s, int n, int l[][],
                           int r[][])
    {
        l[s.charAt(0) - 'a'][0] = 1;
 
        // Precompute the prefix 2D array
        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;
 
        // Precompute the Suffix 2D array.
        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]++;
        }
    }
 
    // Find the number of palindromic subsequence of
    // length k
    static int countPalindromes(int k, int n, int l[][],
                                int r[][])
    {
        int ans = 0;
 
        // If k is 1.
        if (k == 1) {
            for (int i = 0; i < MAX_CHAR; i++)
                ans += l[i][n - 1];
 
            return ans;
        }
 
        // If k is 2
        if (k == 2) {
 
            // Adding all the products of prefix array
            for (int i = 0; i < MAX_CHAR; i++)
                ans += ((l[i][n - 1] * (l[i][n - 1] - 1))
                        / 2);
 
            return ans;
        }
 
        // For k greater than 2. Adding all the products
        // of value of prefix and suffix array.
        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;
    }
 
    // Driver code
    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));
    }
}
 
// This code is contributed by Anant Agarwal.


Python3




# Python3 program to count number of
# subsequences of given length.
 
MAX = 100
MAX_CHAR = 26
 
# Precompute the prefix and suffix array.
def precompute(s, n, l, r):
    l[ord(s[0]) - ord('a')][0] = 1
 
    # Precompute the prefix 2D array
    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
 
    # Precompute the Suffix 2D array.
    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
 
# Find the number of palindromic
# subsequence of length k
def countPalindromes(k, n, l, r):
    ans = 0
 
    # If k is 1.
    if (k == 1):
        for i in range(MAX_CHAR):
            ans += l[i][n - 1]
        return ans
 
    # If k is 2
    if (k == 2):
         
        # Adding all the products of
        # prefix array
        for i in range(MAX_CHAR):
            ans += ((l[i][n - 1] * (l[i][n - 1] - 1)) / 2)
        return ans
     
    # For k greater than 2. Adding all
    # the products of value of prefix
    # and suffix array.
    for i in range(1, n - 1):
        for j in range(MAX_CHAR):
            ans += l[j][i - 1] * r[j][i + 1]
    return ans
 
# Driven Program
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))
 
 
# This code is written by Sachin Bisht


C#




// C# program to count number of
// subsequences of given length.
using System;
class GFG {
     
static int MAX=100;
static int MAX_CHAR=26;
 
// Precompute the prefix
// and suffix array.
static void precompute(string s, int n,
                    int [,]l, int [,]r)
{
    l[s[0] - 'a',0] = 1;
 
    // Precompute the
    // prefix 2D array
    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;
 
    // Precompute the Suffix 2D array.
    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]++;
    }
}
 
// Find the number of palindromic
// subsequence of length k
static int countPalindromes(int k, int n,
                      int [,]l, int [,]r)
{
    int ans = 0;
 
    // If k is 1.
    if (k == 1)
    {
        for (int i = 0; i < MAX_CHAR; i++)
            ans += l[i,n - 1];
         
        return ans;
    }
 
    // If k is 2
    if (k == 2) {
 
        // Adding all the products
        // of prefix array
        for (int i = 0; i < MAX_CHAR; i++)            
            ans += ((l[i,n - 1] *
                    (l[i,n - 1] - 1)) / 2);
         
        return ans;
    }
 
    // For k greater than 2.
    // Adding all the products
    // of value of prefix and
    // suffix array.
    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;
}
     
// Driver code
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));
}
}
 
// This code is contributed by Nitin Mittal.


Javascript




<script>
// Javascript program to count number of subsequences of
// given length.
     
let MAX=100;
let MAX_CHAR=26;
 
// Precompute the prefix and suffix array.
function precompute(s,n,l,r)
{
        l[s[0].charCodeAt(0) - 'a'.charCodeAt(0)][0] = 1;
   
    // Precompute the prefix 2D array
    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;
   
    // Precompute the Suffix 2D array.
    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]++;
    }
}
 
// Find the number of palindromic subsequence of
// length k
function countPalindromes(k,n,l,r)
{
    let ans = 0;
   
    // If k is 1.
    if (k == 1) {
        for (let i = 0; i < MAX_CHAR; i++)
            ans += l[i][n - 1];
           
        return ans;
    }
   
    // If k is 2
    if (k == 2) {
   
        // Adding all the products of prefix array
        for (let i = 0; i < MAX_CHAR; i++)            
            ans += ((l[i][n - 1] * (l[i][n - 1] - 1)) / 2);
           
        return ans;
    }
   
    // For k greater than 2. Adding all the products
    // of value of prefix and suffix array.
    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;
}
 
// Driver code
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));
     
    // This code is contributed by avanitrachhadiya2155
</script>


PHP




<?php
// PHP program to count number of
// subsequences of given length.
$MAX = 100;
$MAX_CHAR = 26;
 
// Precompute the prefix and suffix array.
function precompute($s, $n, &$l, &$r)
{
    global $MAX, $MAX_CHAR;
    $l[ord($s[0]) - ord('a')][0] = 1;
 
    // Precompute the prefix 2D array
    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;
 
    // Precompute the Suffix 2D array.
    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]++;
    }
}
 
// Find the number of palindromic
// subsequence of length k
function countPalindromes($k, $n, &$l, &$r)
{
    global $MAX, $MAX_CHAR;
    $ans = 0;
 
    // If k is 1.
    if ($k == 1)
    {
        for ($i = 0; $i < $MAX_CHAR; $i++)
            $ans += $l[$i][$n - 1];
        return $ans;
    }
 
    // If k is 2
    if ($k == 2)
    {
 
        // Adding all the products of
        // prefix array
        for ($i = 0; $i < $MAX_CHAR; $i++)            
            $ans += (($l[$i][$n - 1] *
                     ($l[$i][$n - 1] - 1)) / 2);
        return $ans;
    }
 
    // For k greater than 2. Adding all
    // the products of value of prefix
    // and suffix array.
    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;
}
 
// Driver Code
$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";
 
// This code is contributed by ita_c
?>


Output

4

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;
 
    // Generate all possible combinations of length k
    vector<string> combinations;
    generateCombinations(&s[0], "", 0, k, combinations);
 
    // Check if combination is a palindrome
    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;
 
        // Generate all possible combinations of length k
        List<String> combinations = new ArrayList<>();
        generateCombinations(s.toCharArray(),
                             new StringBuilder(), 0, k,
                             combinations);
 
        // Check if combination is a palindrome
        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
     
    # Generate all possible combinations of length k
    from itertools import combinations
    for sub in combinations(s, k):
        # Check if combination is a palindrome
        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;
 
        // Generate all possible combinations of length k
        List<string> combinations = new List<string>();
        GenerateCombinations(s.ToCharArray(), "", 0, k, combinations);
 
        // Check if combination is a palindrome
        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;
 
    // Generate all possible combinations of length k
    let combinations = getCombinations(s.split(''), k);
    for (let sub of combinations) {
        // Check if combination is a palindrome
        if (is_palindrome(sub.join(''))) {
            count += 1;
        }
    }
 
    return count;
}
 
// Helper function to generate all combinations of an array
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));


Output

4

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.



Last Updated : 25 Sep, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads