Open In App

Count of Strings of Array having given prefixes for Q query

Last Updated : 30 Jan, 2023
Comments
Improve
Suggest changes
Like Article
Like
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])


Next Article

Similar Reads