Count of Strings of Array having given prefixes for Q query
Last Updated :
30 Jan, 2023
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++
#include <bits/stdc++.h>
using namespace std;
vector< int > GeekAndString(vector<string>& words,
vector<string>& Queries)
{
vector< int > ans;
for (string x : Queries) {
int count = 0;
for (string word : words) {
if (word.size() < x.size())
continue ;
if (word.substr(0, x.size()) == x)
count++;
}
ans.push_back(count);
}
return ans;
}
int main()
{
vector<string> words
= { "geekf" , "geeks" , "geeksforgeeks" ,
"string" , "strong" };
vector<string> queries = { "geek" , "gel" , "str" };
vector< int > ans = GeekAndString(words, queries);
for ( int x : ans)
cout << x << " " ;
return 0;
}
|
Java
import java.util.*;
class GFG {
public static void main(String[] args)
{
String[] words = { "geekf" , "geeks" , "geeksforgeeks" ,
"string" , "strong" };
String[] queries = { "geek" , "gel" , "str" };
ArrayList<Integer> ans
= GeekAndString(words, queries);
for ( int count : ans) {
System.out.print(count + " " );
}
System.out.println();
}
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
def GeekAndString(words, Queries) :
ans = [];
for x in Queries :
count = 0 ;
for word in words :
if len (word) < len (x) :
continue ;
if (word[ 0 : len (x)] = = x) :
count + = 1 ;
ans.append(count);
return ans;
if __name__ = = "__main__" :
words = [ "geekf" , "geeks" , "geeksforgeeks" , "string" , "strong" ];
queries = [ "geek" , "gel" , "str" ];
ans = GeekAndString(words, queries);
for x in ans:
print (x,end = " " );
|
C#
using System;
using System.Collections;
class GFG {
public static void Main( string [] args)
{
string [] words
= { "geekf" , "geeks" , "geeksforgeeks" , "string" ,
"strong" };
string [] queries = { "geek" , "gel" , "str" };
ArrayList ans = GeekAndString(words, queries);
foreach ( int count in ans)
{
Console.Write(count + " " );
}
Console.WriteLine();
}
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;
}
}
|
Javascript
const GeekAndString = (words, Queries) => {
let ans = [];
for (let x in Queries) {
let count = 0;
for (let word in words) {
if (words[word].length < Queries[x].length)
continue ;
if (words[word].substring(0, Queries[x].length) == Queries[x])
count++;
}
ans.push(count);
}
return ans;
}
let words = [ "geekf" , "geeks" , "geeksforgeeks" , "string" , "strong" ];
let queries = [ "geek" , "gel" , "str" ];
let ans = GeekAndString(words, queries);
for (let x in ans)
console.log(`${ans[x]} `);
|
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++
#include <bits/stdc++.h>
using namespace std;
int x;
struct trie {
int cnt;
trie* ch[26];
trie()
{
cnt = 0;
for ( int i = 0; i < 26; i++)
ch[i] = NULL;
}
};
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' ];
}
}
}
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;
}
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;
}
int main()
{
vector<string> words
= { "geekf" , "geeks" , "geeksforgeeks" ,
"string" , "strong" };
vector<string> queries = { "geek" , "gel" , "str" };
vector< int > ans = prefixCount(
words.size(), queries.size(), words, queries);
for ( int count : ans)
cout << count << " " ;
return 0;
}
|
Java
import java.util.*;
class GFG {
public static void main(String[] args)
{
String[] words
= { "geekf" , "geeks" , "geeksforgeeks" ,
"string" , "strong" };
String[] queries = { "geek" , "gel" , "str" };
ArrayList<Integer> ans
= GeekAndString(words, queries);
for ( int count : ans)
System.out.print(count + " " );
}
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;
}
}
class TrieNode {
TrieNode[] links;
int counter;
TrieNode()
{
this .links = new TrieNode[ 26 ];
this .counter = 0 ;
}
}
class Trie {
private TrieNode root;
Trie() { this .root = new TrieNode(); }
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 ;
}
}
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
class Trie:
def __init__( self ):
self .cnt = 0
self .ch = [ None ] * 26
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' )]
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
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
words = [ "geekf" , "geeks" , "geeksforgeeks" , "string" , "strong" ]
queries = [ "geek" , "gel" , "str" ]
ans = prefixCount( len (words), len (queries), words, queries)
print (ans)
|
C#
using System;
using System.Collections.Generic;
public class TrieNode {
public TrieNode[] links;
public int counter;
public TrieNode()
{
this .links = new TrieNode[26];
this .counter = 0;
}
}
public class Trie {
private TrieNode root;
public Trie() { this .root = new TrieNode(); }
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;
}
}
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 {
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()
{
string [] words
= { "geekf" , "geeks" , "geeksforgeeks" , "string" ,
"strong" };
string [] queries = { "geek" , "gel" , "str" };
List< int > ans = GeekAndString(words, queries);
foreach ( int count in ans)
Console.Write(count + " " );
}
}
|
Javascript
let x;
class trie {
constructor(){
this .cnt=0;
this .ch= new Array(26);
}
};
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 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 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;
}
let words
= [ "geekf" , "geeks" , "geeksforgeeks" ,
"string" , "strong" ];
let queries = [ "geek" , "gel" , "str" ];
let ans = prefixCount(
words.length, queries.length, words, queries);
console.log(ans);
|
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])
Share your thoughts in the comments
Please Login to comment...