Count of Strings of Array having given prefixes for Q query


In this problem, we will count the number of strings containing query string as a prefix for each query string.

We can traverse the list of query strings, and for each query, we can find a number of strings containing it as a prefix. Also, we can use the trie data structure to solve the problem.

Problem statement – We have given an strs[] and queStr[] string array containing N and Q strings, respectively. We need to count the number of strings from the Strs[] array containing the queStr[i] string as a prefix for each string of the queStr[] array.

Sample examples

Input

strs = {"tutorial", "tutorials", "tutorialspoint", "tut", "pqe"}; queStr = {"tutorials", 
"tuto", "pq"};

Output

2, 3, 1

  • The 'tutorials' and 'tutorialspoint' contains the 'tutorials' query as a prefix.

  • The tutorial ', 'tutorials', and 'tutorialspoint' contains the 'tuto' query string as a prefix.

  • The only 'pqe' string contains the 'pq' string as a prefix.

Input

strs = {"abcd", "abe", "abp", "rew", "wel"}; queStr = {"ab", "abn", "mo"};

Output

3, 0, 0

Explanation

  • The 'abcd', 'abe', and 'abp' string contains the 'ab' as a prefix.

  • Any string doesn't contain 'abn' and 'mo' as a prefix.

Input

strs = {"aaa", "aaa", "aaa"}; queStr = {"a", "aa", "aaa"};

Output

3, 3, 3

Explanation - All strings contain all queries as a prefix.

Approach 1

In this approach, we will traverse through the array of queries. We can traverse the string array for each query and count the strings containing the query as a prefix. To check whether the string contains the query as a prefix, we can take a substring equal to the query's length from the substring and match it with the query.

Algorithm

Step 1 - Create a list named 'counts'.

Step 2 - Start traversing the queStr[] array of queries and initialize the 'cnt' with 0 in each iteration.

Step 3 - Start traversing the strs[] array, and if the string size is less than the query size, move to the next iteration.

Step 4 - Use the substr() method to get the substring from the 0th index and length equal to the query's length. If the substring equals the query, increment the 'cnt' value by 1.

Step 5 - Insert the 'cnt' value into the 'counts' list.

Step 6 - Return the 'counts' list.

Example

#include <bits/stdc++.h>
using namespace std;

vector<int> findPrefixCounts(vector<string> &strs, vector<string> &queStr) {
   vector<int> counts;
   for (string que : queStr) {
     // To store count of string containing x as prefix
     int cnt = 0;
     for (string str : strs) {
       // For query's greater length than string
       if (str.size() < que.size()) {
         continue;
       }
       // For string containing query as prefix
       if (str.substr(0, que.size()) == que) {
         cnt++;
       }
     }
     // Insert count to vector
     counts.push_back(cnt);
   }
   return counts;
}
int main() {
   // List of strings and Queries
   vector<string> strs = {"tutorial", "tutorials", "tutorialspoint", "tut", "pqe"};
   vector<string> queStr = {"tutorials", "tuto", "pq"};
   vector<int> counts = findPrefixCounts(strs, queStr);
   // Printing the counts
   for (int cnt : counts) {
     cout << cnt << ", ";
   }
   return 0;
}

Output

2, 3, 1,

Time complexity - O(N*Q*S), where N is the length of the string array, Q is the length of the queries array, and S is the maximum length of strings to get a substring.

Space complexity - O(Q) to store counts for each query.

Approach 2

We will use the trie data strucutre to solve the problem in this approach. The trie is called prefix-tree, which we can use to search for strings in large datasets.

It stores the character at each node, and the root node contains the empty string. Here, we will use the linked list to create a trie. Also, we will store the character and count of branches for each node.

We store the prefix counts to each node, representing the number of strings containing the same prefix. After that, while finding the query as a prefix, we can use the prefix count of the last character of the query string as an answer.

Algorithm

Step 1 - Create a 'treeNode' named struct, representing the node of the Trie data structure.

Step 2 - Define the 'prefCnt' variable and array of type 'trieNode', which has a size equal to 26 inside the node. Also, use the constructor to initialize the 'prefCnt' with 0 and all array elements with Null.

Step 3 - Define the createTrie() function to build the trie.

Step 3.1 - Define the 'temp' node in the createTrie() function.

Step 3.2 - Traverse each string of the array, and initialize the 'temp' node with 'head'. Also, traversing the string characters.

Step 3.3 - In the temp node, if the array contains null at the index equal to the character value, add a new node to the index.

Step 3.4 - Increment the 'prefCnt' by 1 of the 'temp' node.

Step 3.5 - Update the temp node according to the current character of the string.

Step 4 - Initialize the 'res' list to store the count of strings containing the query as a prefix.

Step 5 - Execute the createList() function to initialize the Trie.

Step 6 - For each query, execute the findQuery() function to get counts and insert to the 'res' list.

Step 6.1 - In the findQuery() function, start traversing the Trie.

Step 6.2 - If the array contains null at the index equal to the character value in the current node, return 0.

Step 6.3 - Update the head according to the current string character.

Step 6.4 - Return the value of the 'prefCnt' of the head node.

Example

#include <bits/stdc++.h>
using namespace std;

int len;
// Trie node
struct trieNode {
   // To store the count of a string with the current prefix
   int prefCnt;
   trieNode *ch[26];
   // Constructor
   trieNode() {
      prefCnt = 0;
      for (int p = 0; p < 26; p++)
         ch[p] = NULL;
   }
};

void createTrie(vector<string> &list, trieNode *head) {
   // Creating the temporary node
   trieNode *temp;
   for (int p = 0; p < len; p++) {
      temp = head;
      // Inserting the string in trieNode
      for (int q = 0; q < list[p].size(); q++) {
         if (temp->ch[list[p][q] - 'a'] == NULL)
            temp->ch[list[p][q] - 'a'] = new trieNode();
         temp->ch[list[p][q] - 'a']->prefCnt += 1;
         temp = temp->ch[list[p][q] - 'a'];
      }
   }
}

int findQuery(string str, trieNode *head) {
   for (int p = 0; p < str.size(); p++) {
      if (head->ch[str[p] - 'a'] == NULL)
         return 0;
      head = head->ch[str[p] - 'a'];
   }
   return head->prefCnt;
}

vector<int> findPrefixCounts(int strs_len, int que_len, 
vector<string> &list, vector<string> &query) {
   vector<int> res;
   len = strs_len;
   trieNode *head = new trieNode();
   // Create a trie
   createTrie(list, head);
   // Finding the count of a string with the current prefix value
   for (int p = 0; p < que_len; p++) {
      res.push_back(findQuery(query[p], head));
   }
   return res;
}

// Driver Code
int main() {
   // List of strings and Queries
   vector<string> strs = {"tutorial", "tutorials", "tutorialspoint", "tut", 
"pqe"};
   vector<string> queStr = {"tutorials", "tuto", "pq"};
   vector<int> counts = findPrefixCounts(strs.size(), queStr.size(), strs, 
queStr);
   // Printing the counts
   for (int cnt : counts) {
      cout << cnt << ", ";
   }
   return 0;
}

Output

2, 3, 1,

Time complexity - (Q*p + N*R), where Q is total queries, N is total strings, p is the length of the longest query, and R is the length of the longest string to insert in the Trie.

Space complexity - O(Q + N*26) to store the counts equal to a number of queries and create trie each node containing an array of size equal to 26.

We have used the Trie data structure to solve the problem efficiently. Whenever we require to get an output based on the string prefixes, we can use the Trie data structure.

Updated on: 29-Aug-2023

123 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements