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


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


Output:

10
4
1


My Personal Notes arrow_drop_up

Striver(underscore)79 at Codechef and codeforces D

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.



Improved By : rituraj_jain