Open In App

Count of Strings of Array having given prefixes for Q query

Last Updated : 30 Jan, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two arrays of strings containing words[] and queries[] having N and Q strings respectively, the task is to find the number of strings from words[] having queries[i] as the prefix for all the strings in queries[].

Examples:

Input: words[] = { “geeks”, “geeks”, “geeks for geeks”, “string”, “strong” }, queries[] = { “geek”, “gel”, “str” }
Output: 3, 0, 2
Explanation:
1st query “geek” is present in 3 words in the list as a prefix, { “geekf”, “geeks”, “geeksforgeeks” }
2nd query “gel” is not present in any word in the list as a prefix 
3rd query “str” is present in 2 words in the list as a prefix, {“string”, “strong”}   

Input: words[] = { “apple”, “app”, “ape”, “alien”, “a”, “box”, “boxing” }, queries[] = { “a”, “ap”, “b”, “app”, “book” }
Output: 5, 3, 2, 2, 0
Explanation:
1st query “a” is present in 5 words in the list as a prefix, { “apple”, “app”, “ape”, “alien”, “a” }
2nd query “ap” is present in 3 words in the list as a prefix, { “apple”, “app”, “ape” }
3rd query “b” is present in 2 words in the list as a prefix, {“box”, “boxing”} 
4th query “app” is present in 2 words in the list as a prefix, {“apple”, “app“}
5th query “book” is not present in any word in the list as a prefix

Naive Approach: The problem can be solved based on the following idea:

For each query traverse through every word in the list and check whether the word has a prefix as current query or not.

  • Create a dummy vector ans, to store the resultant array.
  • Start traversing queries[] and initialize a counter variable count to store the count of words that have prefixes as the current query.
    • If the size of any word at any ith iteration is less than the size of the query, skip the iteration.
    • If the prefix is found in words[] then increment the counter variable.
    • Push count of prefixes in the vector ans.
  • Return the ans. 

Below is the implementation of the above approach.

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to return an array containing
// the number of words having the given prefix
// for each query
vector<int> GeekAndString(vector<string>& words,
                          vector<string>& Queries)
{
    vector<int> ans;
    for (string x : Queries) {
 
        // To count number of
        // matching prefixes in word array
        int count = 0;
        for (string word : words) {
 
            if (word.size() < x.size())
                continue;
 
            // If prefix found then increment counter
            if (word.substr(0, x.size()) == x)
                count++;
        }
        ans.push_back(count);
    }
 
    return ans;
}
 
// Driver Code
int main()
{
 
    vector<string> words
        = { "geekf", "geeks", "geeksforgeeks",
            "string", "strong" };
 
    vector<string> queries = { "geek", "gel", "str" };
 
    // Function call
    vector<int> ans = GeekAndString(words, queries);
    for (int x : ans)
        cout << x << " ";
 
    return 0;
}


Java




// Java code to implement the approach
 
import java.util.*;
 
class GFG {
 
    // Driver Code
    public static void main(String[] args)
    {
        String[] words = { "geekf", "geeks", "geeksforgeeks",
                           "string", "strong" };
        String[] queries = { "geek", "gel", "str" };
 
        // Function call
        ArrayList<Integer> ans
            = GeekAndString(words, queries);
 
        for (int count : ans) {
            System.out.print(count + " ");
        }
        System.out.println();
    }
 
    // Function to return an array
    // containing the number of words
    // having given prefix for each query
    public static ArrayList<Integer>
        GeekAndString(String[] Li, String[] Queries)
    {
 
        ArrayList<Integer> answer = new ArrayList<>();
        for (String x : Queries) {
            int count = 0;
            for (String word : Li) {
 
                if (word.length() < x.length())
                    continue;
 
                if (x.equals(
                        word.substring(0, x.length()))) {
                    count++;
                }
            }
            answer.add(count);
        }
        return answer;
    }
}


Python3




# Python3 code to implement the approach
 
# Function to return an array containing
# the number of words having the given prefix
# for each query
def GeekAndString(words, Queries) :
    ans = [];
    for x in Queries :
 
        # To count number of number of
        # matching prefixes in word array
        count = 0;
        for word in words :
 
            if len(word) < len(x) :
                continue;
 
            # If prefix found then increment counter
            if (word[0 : len(x)] == x) :
                count += 1;
 
        ans.append(count);
 
    return ans;
 
# Driver Code
if __name__ == "__main__" :
 
    words = [ "geekf", "geeks", "geeksforgeeks","string", "strong" ];
    queries = [ "geek", "gel", "str" ];
 
    # Function call
    ans = GeekAndString(words, queries);
    for x in ans:
        print(x,end=" ");
 
    # This code is contributed by AnkThon


C#




// C# code to implement the approach
using System;
using System.Collections;
 
class GFG {
 
  // Driver Code
  public static void Main(string[] args)
  {
    string[] words
      = { "geekf", "geeks", "geeksforgeeks", "string",
         "strong" };
    string[] queries = { "geek", "gel", "str" };
 
    // Function call
    ArrayList ans = GeekAndString(words, queries);
 
    foreach(int count in ans)
    {
      Console.Write(count + " ");
    }
    Console.WriteLine();
  }
 
  // Function to return an array
  // containing the number of words
  // having given prefix for each query
  public static ArrayList GeekAndString(string[] Li,
                                        string[] Queries)
  {
 
    ArrayList answer = new ArrayList();
    foreach(string x in Queries)
    {
      int count = 0;
      foreach(string word in Li)
      {
 
        if (word.Length < x.Length)
          continue;
 
        if (x.Equals(word.Substring(0, x.Length))) {
          count++;
        }
      }
      answer.Add(count);
    }
    return answer;
  }
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript




// JavaScript code to implement the approach
 
// Function to return an array containing
// the number of words having the given prefix
// for each query
const GeekAndString = (words, Queries) => {
    let ans = [];
    for (let x in Queries) {
 
        // To count number of number of
        // matching prefixes in word array
        let count = 0;
        for (let word in words) {
 
            if (words[word].length < Queries[x].length)
                continue;
 
            // If prefix found then increment counter
            if (words[word].substring(0, Queries[x].length) == Queries[x])
                count++;
        }
        ans.push(count);
    }
 
    return ans;
}
 
// Driver Code
let words = ["geekf", "geeks", "geeksforgeeks", "string", "strong"];
 
let queries = ["geek", "gel", "str"];
 
// Function call
let ans = GeekAndString(words, queries);
for (let x in ans)
    console.log(`${ans[x]} `);
 
// This code is contributed by rakeshsahni


Output

3 0 2 

Time Complexity: O(N * Q * M), where M = maximum length of a string in queries[]
Auxiliary Space: O(N)

Efficient approach: The problem can be solved efficiently on the basis of the following approach

We have to use such a data structure to match the string to find out if it is prefix of another string in optimal time. Trie can help us in this problem.

Build a trie and insert the strings of word[] in the trie. where each node will also keep a count of strings with that prefix. Then while traversing through queries[] find the prefix and the count associated with it. The structure of a trie node will be like the following:

  • children: This field is used for mapping from a character to the next level trie node
  • isEndOfWord: This field is used to distinguish the node as end of word node
  • num: This field is used to count the number of times a node is visited during insertion in trie

Follow the steps mentioned below to implement the idea:

  • Insert the list of strings in trie such that every string in the list is inserted as an individual trie node.
  • During inserting update all the fields in every node of the trie
  • For each query, traverse the trie till we reach the last character of the given prefix queries[i].
  • The value of the num field in the last node of the prefix is the count of strings of words[] having the given prefix.
  • For each query, store this num, in an answer vector. 

Below is the implementation of the above approach:

C++




// C++ code to implement the approach
 
#include <bits/stdc++.h>
using namespace std;
int x;
 
// Structure of a trie node
struct trie {
    int cnt;
    trie* ch[26];
    trie()
    {
        cnt = 0;
        for (int i = 0; i < 26; i++)
            ch[i] = NULL;
    }
};
 
// Function to build the trie
void build(vector<string>& a, trie* root)
{
    trie* temp;
    for (int i = 0; i < x; i++) {
        temp = root;
        for (int j = 0; j < a[i].size(); j++) {
            if (temp->ch[a[i][j] - 'a'] == NULL)
                temp->ch[a[i][j] - 'a'] = new trie();
            temp->ch[a[i][j] - 'a']->cnt += 1;
            temp = temp->ch[a[i][j] - 'a'];
        }
    }
}
 
// Function to find a string in the trie
int find(string s, trie* root)
{
    for (int i = 0; i < s.size(); i++) {
        if (root->ch[s[i] - 'a'] == NULL)
            return 0;
        root = root->ch[s[i] - 'a'];
    }
    return root->cnt;
}
 
// Function to get the given number of string
// having the same prefix as the query
vector<int> prefixCount(int N, int Q,
                        vector<string>& list,
                        vector<string>& query)
{
    vector<int> res;
    x = N;
    trie* root = new trie();
    build(list, root);
    for (int i = 0; i < Q; i++)
        res.push_back(find(query[i], root));
    return res;
}
 
// Driver Code
int main()
{
    vector<string> words
        = { "geekf", "geeks", "geeksforgeeks",
            "string", "strong" };
    vector<string> queries = { "geek", "gel", "str" };
 
    // Function call
    vector<int> ans = prefixCount(
        words.size(), queries.size(), words, queries);
 
    for (int count : ans)
        cout << count << " ";
 
    return 0;
}


Java




// Java code to implement the approach
 
import java.util.*;
 
class GFG {
 
    // Driver Code
    public static void main(String[] args)
    {
 
        String[] words
            = { "geekf", "geeks", "geeksforgeeks",
                "string", "strong" };
        String[] queries = { "geek", "gel", "str" };
 
        // Function call
        ArrayList<Integer> ans
            = GeekAndString(words, queries);
 
        for (int count : ans)
            System.out.print(count + " ");
    }
 
    // Function to get the given number of string
    // having the same prefix as the query
    public static ArrayList<Integer>
        GeekAndString(String[] Li, String[] Queries)
    {
 
        ArrayList<Integer> answer = new ArrayList<>();
 
        Trie trie = new Trie();
 
        for (String word : Li) {
            trie.inert(word);
        }
 
        for (String word : Queries) {
            answer.add(trie.query(word));
        }
 
        return answer;
    }
}
 
// Structure of a trie node
class TrieNode {
    TrieNode[] links;
    int counter;
 
    TrieNode()
    {
        this.links = new TrieNode[26];
        this.counter = 0;
    }
}
 
// Structure of a trie
class Trie {
    private TrieNode root;
 
    Trie() { this.root = new TrieNode(); }
 
    // Function to insert the string in the trie
    public void inert(String word)
    {
        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            int pos = (word.charAt(i) - 'a');
 
            if (node.links[pos] == null) {
                node.links[pos] = new TrieNode();
            }
            node = node.links[pos];
            node.counter = node.counter + 1;
        }
    }
 
    // Function to find answer for each query
    public int query(String word)
    {
        TrieNode node = root;
        for (int i = 0; i < word.length(); i++) {
            int pos = (word.charAt(i) - 'a');
 
            if (node.links[pos] == null) {
                return 0;
            }
            node = node.links[pos];
        }
        return node.counter;
    }
}


Python




# Python code to implement the above approach
 
# Structure of a trie node
class Trie:
    def __init__(self):
        self.cnt = 0
        self.ch = [None] * 26
 
# Function to build the trie
def build(a, root):
    temp = None
    for i in range(len(a)):
        temp = root
        for j in range(len(a[i])):
            if not temp.ch[ord(a[i][j]) - ord('a')]:
                temp.ch[ord(a[i][j]) - ord('a')] = Trie()
            temp.ch[ord(a[i][j]) - ord('a')].cnt += 1
            temp = temp.ch[ord(a[i][j]) - ord('a')]
 
# Function to find a string in the trie
def find(s, root):
    for i in range(len(s)):
        if not root.ch[ord(s[i]) - ord('a')]:
            return 0
        root = root.ch[ord(s[i]) - ord('a')]
    return root.cnt
 
# Function to get the given number of string
# having the same prefix as the query
def prefixCount(N, Q, list, query):
    res = []
    root = Trie()
    build(list, root)
    for i in range(Q):
        res.append(find(query[i], root))
    return res
 
# Driver Code
words = ["geekf", "geeks", "geeksforgeeks","string", "strong"]
queries = ["geek", "gel", "str"]
 
# Function call
ans = prefixCount(len(words), len(queries), words, queries)
 
print(ans)


C#




// C# code to implement the approach
using System;
using System.Collections.Generic;
 
// Structure of a trie node
public class TrieNode {
  public TrieNode[] links;
  public int counter;
 
  public TrieNode()
  {
    this.links = new TrieNode[26];
    this.counter = 0;
  }
}
 
// Structure of a trie
public class Trie {
  private TrieNode root;
 
  public Trie() { this.root = new TrieNode(); }
 
  // Function to insert the string in the trie
  public void Insert(string word)
  {
    TrieNode node = root;
    for (int i = 0; i < word.Length; i++) {
      int pos = (word[i] - 'a');
 
      if (node.links[pos] == null) {
        node.links[pos] = new TrieNode();
      }
      node = node.links[pos];
      node.counter = node.counter + 1;
    }
  }
 
  // Function to find answer for each query
  public int Query(string word)
  {
    TrieNode node = root;
    for (int i = 0; i < word.Length; i++) {
      int pos = (word[i] - 'a');
 
      if (node.links[pos] == null) {
        return 0;
      }
      node = node.links[pos];
    }
    return node.counter;
  }
}
 
public class GFG {
 
  // Function to get the given number of string
  // having the same prefix as the query
  static List<int> GeekAndString(string[] Li,
                                 string[] Queries)
  {
    List<int> answer = new List<int>();
 
    Trie trie = new Trie();
 
    foreach(string word in Li) { trie.Insert(word); }
 
    foreach(string word in Queries)
    {
      answer.Add(trie.Query(word));
    }
 
    return answer;
  }
 
  static public void Main()
  {
 
    // Code
    string[] words
      = { "geekf", "geeks", "geeksforgeeks", "string",
         "strong" };
    string[] queries = { "geek", "gel", "str" };
 
    // Function call
    List<int> ans = GeekAndString(words, queries);
 
    foreach(int count in ans)
      Console.Write(count + " ");
  }
}
 
// This code is contributed by lokeshmvs21.


Javascript




// Javascript code to implement the approach
let x;
 
// Structure of a trie node
class trie {
    constructor(){
    this.cnt=0;
    this.ch= new Array(26);
    }
};
 
// Function to build the trie
function build( a, root)
{
    let temp=new trie();
    for (let i = 0; i < x; i++) {
        temp = root;
        for (let j = 0; j < a[i].length; j++) {
            let x= a[i].charCodeAt(j)-97;
            if (temp.ch[x] == null)
                temp.ch[x] = new trie();
            temp.ch[x].cnt += 1;
            temp = temp.ch[x];
        }
    }
}
 
// Function to find a string in the trie
function find( s, root)
{
    for (let i = 0; i < s.length; i++) {
        let x= s.charCodeAt(i)-97;
        if (root.ch[x] == null)
            return 0;
        root = root.ch[x];
    }
    return root.cnt;
}
 
// Function to get the given number of string
// having the same prefix as the query
function prefixCount(N, Q,list, query)
{
    let res=[];
    x = N;
    let root = new trie();
    build(list, root);
    for (let i = 0; i < Q; i++)
        res.push(find(query[i], root));
    return res;
}
 
// Driver Code
 
    let words
        = [ "geekf", "geeks", "geeksforgeeks",
            "string", "strong" ];
    let queries = [ "geek", "gel", "str" ];
 
    // Function call
    let ans = prefixCount(
        words.length, queries.length, words, queries);
 
    console.log(ans);
 
   // This code is contributed by garg28harsh.


Output

3 0 2 

Time Complexity: O(Q * x + N*L),  Where x is the longest word in the query, and L = length of the longest word inserted in the trie.
Auxiliary Space: O(N * List [i])



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads