Number of ways of choosing K equal substrings of any length for every query

Given a string str and Q queries. Each query consists of an integer K. The task is to find the number of ways of choosing K equal sub-strings of any length possible for every query. Note that the set of K substrings must be unique.

Examples:

Input: str = “aabaab”, que[] = {3}
Output: 4
“a” is the only sub-string that appears more than 3 times i.e. 4.
And there are 4 ways of choosing 3 different strings from the given 4 strings.



Input: str = “aggghh”, que[] = {1, 2, 3}
Output:
21
5
1

Approach: The following steps can be followed to solve the problem and answer every query in the minimal possible time.

  • Generate all the substrings for a string and count the occurrence of every unique substring using hashing.
  • For every query, the answer will to choose K substrings of every string which occurs for more than K times(say X). The answer will be X \choose K
  • The time complexity per query can be reduced by pre-computing the binomial co-efficient

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
#define maxlen 100
  
// Function to generate all the sub-strings
void generateSubStrings(string s, unordered_map<string,
                                                int>& mpp)
{
  
    // Length of the string
    int l = s.length();
  
    // Generate all sub-strings
    for (int i = 0; i < l; i++) {
        string temp = "";
        for (int j = i; j < l; j++) {
            temp += s[j];
  
            // Count the occurrence of
            // every sub-string
            mpp[temp] += 1;
        }
    }
}
  
// Compute the Binomial Coefficient
void binomialCoeff(int C[maxlen][maxlen])
{
    int i, j;
  
    // Calculate value of Binomial Coefficient
    // in bottom up manner
    for (i = 0; i < 100; i++) {
        for (j = 0; j < 100; j++) {
  
            // Base Cases
            if (j == 0 || j == i)
                C[i][j] = 1;
  
            // Calculate value using previously
            // stored values
            else
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
    }
}
  
// Function to return the result for a query
int answerQuery(unordered_map<string, int>& mpp,
                int C[maxlen][maxlen], int k)
{
    int ans = 0;
  
    // Iterate for every
    // unique sub-string
    for (auto it : mpp) {
  
        // Count the combinations
        if (it.second >= k)
            ans += C[it.second][k];
    }
  
    return ans;
}
  
// Driver code
int main()
{
    string s = "aabaab";
  
    // Get all the sub-strings
    // Store the occurrence of
    // all the sub-strings
    unordered_map<string, int> mpp;
    generateSubStrings(s, mpp);
  
    // Pre-computation
    int C[maxlen][maxlen];
    memset(C, 0, sizeof C);
    binomialCoeff(C);
  
    // Queries
    int queries[] = { 2, 3, 4 };
    int q = sizeof(queries) / sizeof(queries[0]);
  
    // Perform queries
    for (int i = 0; i < q; i++)
        cout << answerQuery(mpp, C, queries[i]) << endl;
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java implementation of the approach 
import java.util.HashMap;
  
class GFG 
{
    static int maxlen = 100;
  
    // Function to generate all the sub-strings
    public static void generateSubStrings(
                       String s, HashMap<String,
                                         Integer> mpp) 
    {
  
        // Length of the string
        int l = s.length();
  
        // Generate all sub-strings
        for (int i = 0; i < l; i++)
        {
            String temp = "";
            for (int j = i; j < l; j++) 
            {
                temp += s.charAt(j);
  
                // Count the occurrence of
                // every sub-string
                if (mpp.containsKey(temp)) 
                {
                    int x = mpp.get(temp);
                    mpp.put(temp, ++x);
                
                else
                    mpp.put(temp, 1);
            }
        }
    }
  
    // Compute the Binomial Coefficient
    public static void binomialCoeff(int[][] C) 
    {
        int i, j;
  
        // Calculate value of Binomial Coefficient
        // in bottom up manner
        for (i = 1; i < 100; i++) 
        {
            for (j = 0; j < 100; j++)
            {
  
                // Base Cases
                if (j == 0 || j == i)
                    C[i][j] = 1;
  
                // Calculate value using previously
                // stored values
                else
                    C[i][j] = C[i - 1][j - 1] + 
                              C[i - 1][j];
            }
        }
    }
  
    // Function to return the result for a query
    public static int answerQuery(HashMap<String,
                                          Integer> mpp, 
                                      int[][] C, int k)
    {
        int ans = 0;
  
        // Iterate for every
        // unique sub-string
        for (HashMap.Entry<String, 
                           Integer> entry : mpp.entrySet()) 
        {
  
            // Count the combinations
            if (entry.getValue() >= k)
                ans += C[entry.getValue()][k];
        }
        return ans;
    }
  
    // Driver code
    public static void main(String[] args) 
    {
        String s = "aabaab";
  
        // Get all the sub-strings
        // Store the occurrence of
        // all the sub-strings
        HashMap<String, 
                Integer> mpp = new HashMap<>();
        generateSubStrings(s, mpp);
  
        // Pre-computation
        int[][] C = new int[maxlen][maxlen];
        binomialCoeff(C);
  
        // Queries
        int[] queries = { 2, 3, 4 };
        int q = queries.length;
  
        // Perform queries
        for (int i = 0; i < q; i++)
            System.out.println(answerQuery(mpp, C, 
                                     queries[i]));
    }
}
  
// This code is contributed by
// sanjeev2552

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 implementation of the approach 
from collections import defaultdict
  
maxlen = 100
  
# Function to generate all the sub-strings 
def generateSubStrings(s, mpp): 
  
    # Length of the string 
    l = len(s) 
  
    # Generate all sub-strings 
    for i in range(0, l): 
        temp = "" 
        for j in range(i, l): 
            temp += s[j] 
  
            # Count the occurrence of 
            # every sub-string 
            mpp[temp] += 1
  
# Compute the Binomial Coefficient 
def binomialCoeff(C): 
  
    # Calculate value of Binomial 
    # Coefficient in bottom up manner 
    for i in range(0, 100): 
        for j in range(0, 100): 
  
            # Base Cases 
            if j == 0 or j == i: 
                C[i][j] = 1
  
            # Calculate value using previously 
            # stored values 
            else:
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j] 
  
# Function to return the result for a query 
def answerQuery(mpp, C, k): 
  
    ans = 0
    # Iterate for every 
    # unique sub-string 
    for it in mpp: 
  
        # Count the combinations 
        if mpp[it] >= k: 
            ans += C[mpp[it]][k] 
  
    return ans 
  
# Driver code 
if __name__ == "__main__":
      
    s = "aabaab"
      
    # Get all the sub-strings 
    # Store the occurrence of 
    # all the sub-strings 
    mpp = defaultdict(lambda:0)
    generateSubStrings(s, mpp) 
  
    # Pre-computation 
    C = [[0 for i in range(maxlen)] 
            for j in range(maxlen)]
    binomialCoeff(C) 
  
    # Queries 
    queries = [2, 3, 4
    q = len(queries) 
  
    # Perform queries 
    for i in range(0, q): 
        print(answerQuery(mpp, C, queries[i]))
          
# This code is contributed by Rituraj Jain

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# code to print level order 
// traversal in sorted order
using System;
using System.Collections.Generic;
  
class GFG 
    static int maxlen = 100;
  
    // Function to generate all the sub-strings
    public static void generateSubStrings(String s, 
                               Dictionary<String, int> mpp) 
    {
  
        // Length of the string
        int l = s.Length;
  
        // Generate all sub-strings
        for (int i = 0; i < l; i++)
        {
            String temp = "";
            for (int j = i; j < l; j++) 
            {
                temp += s[j];
  
                // Count the occurrence of
                // every sub-string
                if (mpp.ContainsKey(temp)) 
                {
                    mpp[temp] = ++mpp[temp];
                
                else
                    mpp.Add(temp, 1);
            }
        }
    }
  
    // Compute the Binomial Coefficient
    public static void binomialCoeff(int[,] C) 
    {
        int i, j;
  
        // Calculate value of Binomial Coefficient
        // in bottom up manner
        for (i = 1; i < 100; i++) 
        {
            for (j = 0; j < 100; j++)
            {
  
                // Base Cases
                if (j == 0 || j == i)
                    C[i, j] = 1;
  
                // Calculate value using previously
                // stored values
                else
                    C[i, j] = C[i - 1, j - 1] + 
                              C[i - 1, j];
            }
        }
    }
  
    // Function to return the result for a query
    public static int answerQuery(Dictionary<String, int> mpp, 
                                           int[,] C, int k)
    {
        int ans = 0;
  
        // Iterate for every
        // unique sub-string
        foreach(KeyValuePair<String, int> entry in mpp) 
        {
  
            // Count the combinations
            if (entry.Value >= k)
                ans += C[entry.Value, k];
        }
        return ans;
    }
  
    // Driver code
    public static void Main(String[] args) 
    {
        String s = "aabaab";
  
        // Get all the sub-strings
        // Store the occurrence of
        // all the sub-strings
        Dictionary<String, 
                   int> mpp = new Dictionary<String,    
                                             int>();
        generateSubStrings(s, mpp);
  
        // Pre-computation
        int[,] C = new int[maxlen, maxlen];
        binomialCoeff(C);
  
        // Queries
        int[] queries = { 2, 3, 4 };
        int q = queries.Length;
  
        // Perform queries
        for (int i = 0; i < q; i++)
            Console.WriteLine(answerQuery(mpp, C, 
                                    queries[i]));
    }
}
  
// This code is contributed by 29AjayKumar

chevron_right


Output:

10
4
1



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.