Given an array of strings s[] and an array of query strings q[], where all strings consist of lowercase English letters, determine for each query string q[i] the number of strings in s[] that have q[i] as a prefix. Return an array res[] such that res[i] denotes the number of strings in s[] that begin with the prefix q[i].
Examples:
Input: s[] = ["abracadabra", "geeksforgeeks", "abracadabra", "geeks", "geeksthrill"], q[] = ["abr", "geeks", "ge", "gar"]
Output: [2, 3, 3, 0]
Explanation: For each query:
"abr" is a prefix of both occurrences of "abracadabra", so the count is 2.
"geeks" is a prefix of "geeksforgeeks", "geeks", and "geeksthrill", so the count is 3.
"ge" is a prefix of "geeksforgeeks", "geeks", and "geeksthrill", so the count is 3.
"gar" is not a prefix of any string in s[], so the count is 0.
Input: s[] = ["apple", "app", "banana", "application"], q[] = ["ap", "ban"]
Output: [3, 1]
Explanation: For each query:
"ap" is a prefix of "apple", "app", and "application", so the count is 3.
"ban" is a prefix of "banana", so the count is 1.
Table of Content
[Naive Approach] Check Every Query Against Every String - O(Q * N * L) Time and O(1) Space
The idea is to process each query independently. For every query string, traverse all strings in the array and check whether the query is a prefix of the current string. Count all such matches and store the result.
#include <iostream>
#include <vector>
using namespace std;
// Checks if pref is a prefix of str.
bool isPrefix(string &str, string &pref)
{
if (pref.size() > str.size())
return false;
for (int i = 0; i < pref.size(); i++)
{
if (str[i] != pref[i])
return false;
}
return true;
}
vector<int> prefCount(vector<string> &s, vector<string> &q)
{
vector<int> res;
// Process each query independently.
for (string &pref : q)
{
int cnt = 0;
// Check every string.
for (string &str : s)
{
if (isPrefix(str, pref))
cnt++;
}
res.push_back(cnt);
}
return res;
}
// Driver code
int main()
{
vector<string> s = {"abracadabra", "geeksforgeeks", "abracadabra", "geeks", "geeksthrill"};
vector<string> q = {"abr", "geeks", "ge", "gar"};
vector<int> res = prefCount(s, q);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << res[i];
if (i != res.size() - 1)
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
// Checks if pref is a prefix of str.
class GFG {
static boolean isPrefix(String str, String pref)
{
if (pref.length() > str.length())
return false;
for (int i = 0; i < pref.length(); i++) {
if (str.charAt(i) != pref.charAt(i))
return false;
}
return true;
}
static ArrayList<Integer> prefCount(ArrayList<String> s,
ArrayList<String> q)
{
ArrayList<Integer> res = new ArrayList<>();
// Process each query independently.
for (String pref : q) {
int cnt = 0;
// Check every string.
for (String str : s) {
if (isPrefix(str, pref))
cnt++;
}
res.add(cnt);
}
return res;
}
// Driver code
public static void main(String[] args)
{
ArrayList<String> s = new ArrayList<>(Arrays.asList(
"abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"));
ArrayList<String> q = new ArrayList<>(
Arrays.asList("abr", "geeks", "ge", "gar"));
ArrayList<Integer> res = prefCount(s, q);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i));
if (i != res.size() - 1)
System.out.print(", ");
}
System.out.print("]");
}
}
# Checks if pref is a prefix of str.
def isPrefix(str, pref):
if len(pref) > len(str):
return False
for i in range(len(pref)):
if str[i] != pref[i]:
return False
return True
def prefCount(s, q):
res = []
# Process each query independently.
for pref in q:
cnt = 0
# Check every string.
for str in s:
if isPrefix(str, pref):
cnt += 1
res.append(cnt)
return res
# Driver code
if __name__ == "__main__":
s = ["abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"]
q = ["abr", "geeks", "ge", "gar"]
res = prefCount(s, q)
print("[", end="")
for i in range(len(res)):
print(res[i], end="")
if i != len(res) - 1:
print(", ", end="")
print("]", end="")
using System;
using System.Collections.Generic;
class GFG {
// Checks if pref is a prefix of str.
static bool isPrefix(string str, string pref)
{
if (pref.Length > str.Length)
return false;
for (int i = 0; i < pref.Length; i++) {
if (str[i] != pref[i])
return false;
}
return true;
}
static List<int> prefCount(List<string> s,
List<string> q)
{
List<int> res = new List<int>();
// Process each query independently.
foreach(string pref in q)
{
int cnt = 0;
// Check every string.
foreach(string str in s)
{
if (isPrefix(str, pref))
cnt++;
}
res.Add(cnt);
}
return res;
}
// Driver code
static void Main()
{
List<string> s = new List<string>{
"abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"
};
List<string> q = new List<string>{ "abr", "geeks",
"ge", "gar" };
List<int> res = prefCount(s, q);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write(res[i]);
if (i != res.Count - 1)
Console.Write(", ");
}
Console.Write("]");
}
}
// Checks if pref is a prefix of str.
function isPrefix(str, pref)
{
if (pref.length > str.length)
return false;
for (let i = 0; i < pref.length; i++) {
if (str[i] !== pref[i])
return false;
}
return true;
}
function prefCount(s, q)
{
let res = [];
// Process each query independently.
for (let pref of q) {
let cnt = 0;
// Check every string.
for (let str of s) {
if (isPrefix(str, pref))
cnt++;
}
res.push(cnt);
}
return res;
}
// Driver code
let s = [
"abracadabra", "geeksforgeeks", "abracadabra", "geeks",
"geeksthrill"
];
let q = [ "abr", "geeks", "ge", "gar" ];
let res = prefCount(s, q);
console.log("[");
for (let i = 0; i < res.length; i++) {
process.stdout.write(res[i].toString());
if (i != res.length - 1)
process.stdout.write(", ");
}
console.log("]");
Output
[2, 3, 3, 0]
[Expected Approach] Trie with Prefix Count - O(N * L + Q * L) Time and O(N * L) Space
The idea is to build a Trie using all strings in the array. Each Trie node stores the number of strings passing through it. For a query, traverse the Trie following its characters. If the prefix exists, return the stored count at the last node; otherwise return 0.
Let us understand with example:
Input: s[] = ["abracadabra", "geeksforgeeks", "abracadabra", "geeks", "geeksthrill"], q[] = ["abr", "geeks", "ge", "gar"]
- Insert all strings into the Trie. While inserting each character, increment the count stored at the corresponding Trie node.
- For query "abr", traverse the Trie along a -> b -> r. The node for "abr" stores count 2, so the answer is 2.
- For query "geeks", the traversal reaches the node for "geeks", which stores count 3, so the answer is 3.
- For query "ge", the node for "ge" stores count 3, so the answer is 3.
- For query "gar", the required path is not present in the Trie, so the answer is 0.
Output: [2, 3, 3, 0]
#include <iostream>
using namespace std;
// Trie node representing a single character.
class TrieNode
{
public:
// Number of words having the prefix represented
// by the path from root to this node.
int cnt;
// Pointers to child nodes for characters 'a' to 'z'.
TrieNode *child[26];
TrieNode()
{
cnt = 0;
for (int i = 0; i < 26; i++)
{
child[i] = nullptr;
}
}
};
// Inserts a word into the trie and updates
// the prefix count at each visited node.
void insert(TrieNode *root, string &word)
{
TrieNode *node = root;
for (char ch : word)
{
int idx = ch - 'a';
// Create a new node if the path does not exist.
if (node->child[idx] == nullptr)
{
node->child[idx] = new TrieNode();
}
node = node->child[idx];
// Increment the count of words passing
// through this prefix node.
node->cnt++;
}
}
// Returns the number of words that start
// with the given prefix.
int countPref(TrieNode *root, string &pref)
{
TrieNode *node = root;
for (char ch : pref)
{
int idx = ch - 'a';
// Prefix not present in the trie.
if (node->child[idx] == nullptr)
{
return 0;
}
node = node->child[idx];
}
// The stored count equals the number of
// words having this prefix.
return node->cnt;
}
vector<int> prefCount(vector<string> &s, vector<string> &q)
{
// Create the root of the trie.
TrieNode *root = new TrieNode();
// Insert all words into the trie.
for (string &word : s)
{
insert(root, word);
}
vector<int> res;
// Answer each query independently.
for (string &pref : q)
{
res.push_back(countPref(root, pref));
}
return res;
}
// Driver code
int main()
{
vector<string> s = {"abracadabra", "geeksforgeeks", "abracadabra", "geeks", "geeksthrill"};
vector<string> q = {"abr", "geeks", "ge", "gar"};
vector<int> res = prefCount(s, q);
cout << "[";
for (int i = 0; i < res.size(); i++)
{
cout << res[i];
if (i != res.size() - 1)
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.*;
// Trie node representing a single character.
class TrieNode {
// Number of words having the prefix represented
// by the path from root to this node.
int cnt;
// Pointers to child nodes for characters 'a' to 'z'.
TrieNode[] child;
TrieNode()
{
cnt = 0;
child = new TrieNode[26];
}
}
class GFG {
// Inserts a word into the trie and updates
// the prefix count at each visited node.
static void insert(TrieNode root, String word)
{
TrieNode node = root;
for (char ch : word.toCharArray()) {
int idx = ch - 'a';
// Create a new node if the path does not exist.
if (node.child[idx] == null) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
// Increment the count of words passing
// through this prefix node.
node.cnt++;
}
}
// Returns the number of words that start
// with the given prefix.
static int countPref(TrieNode root, String pref)
{
TrieNode node = root;
for (char ch : pref.toCharArray()) {
int idx = ch - 'a';
// Prefix not present in the trie.
if (node.child[idx] == null) {
return 0;
}
node = node.child[idx];
}
// The stored count equals the number of
// words having this prefix.
return node.cnt;
}
static ArrayList<Integer> prefCount(ArrayList<String> s,
ArrayList<String> q)
{
// Create the root of the trie.
TrieNode root = new TrieNode();
// Insert all words into the trie.
for (String word : s) {
insert(root, word);
}
ArrayList<Integer> res = new ArrayList<>();
// Answer each query independently.
for (String pref : q) {
res.add(countPref(root, pref));
}
return res;
}
// Driver code
public static void main(String[] args)
{
ArrayList<String> s = new ArrayList<>(Arrays.asList(
"abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"));
ArrayList<String> q = new ArrayList<>(
Arrays.asList("abr", "geeks", "ge", "gar"));
ArrayList<Integer> res = prefCount(s, q);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i));
if (i != res.size() - 1) {
System.out.print(", ");
}
}
System.out.print("]");
}
}
# Trie node representing a single character.
class TrieNode:
def __init__(self):
# Number of words having the prefix represented
# by the path from root to this node.
self.cnt = 0
# Pointers to child nodes for characters 'a' to 'z'.
self.child = [None] * 26
# Inserts a word into the trie and updates
# the prefix count at each visited node.
def insert(root, word):
node = root
for ch in word:
idx = ord(ch) - ord('a')
# Create a new node if the path does not exist.
if node.child[idx] is None:
node.child[idx] = TrieNode()
node = node.child[idx]
# Increment the count of words passing
# through this prefix node.
node.cnt += 1
# Returns the number of words that start
# with the given prefix.
def countPref(root, pref):
node = root
for ch in pref:
idx = ord(ch) - ord('a')
# Prefix not present in the trie.
if node.child[idx] is None:
return 0
node = node.child[idx]
# The stored count equals the number of
# words having this prefix.
return node.cnt
def prefCount(s, q):
# Create the root of the trie.
root = TrieNode()
# Insert all words into the trie.
for word in s:
insert(root, word)
res = []
# Answer each query independently.
for pref in q:
res.append(countPref(root, pref))
return res
# Driver code
if __name__ == "__main__":
s = ["abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"]
q = ["abr", "geeks", "ge", "gar"]
res = prefCount(s, q)
print("[", end="")
for i in range(len(res)):
print(res[i], end="")
if i != len(res) - 1:
print(", ", end="")
print("]", end="")
using System;
using System.Collections.Generic;
// Trie node representing a single character.
class TrieNode {
// Number of words having the prefix represented
// by the path from root to this node.
public int cnt;
// Pointers to child nodes for characters 'a' to 'z'.
public TrieNode[] child;
public TrieNode()
{
cnt = 0;
child = new TrieNode[26];
}
}
class GFG {
// Inserts a word into the trie and updates
// the prefix count at each visited node.
static void insert(TrieNode root, string word)
{
TrieNode node = root;
foreach(char ch in word)
{
int idx = ch - 'a';
// Create a new node if the path does not exist.
if (node.child[idx] == null) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
// Increment the count of words passing
// through this prefix node.
node.cnt++;
}
}
// Returns the number of words that start
// with the given prefix.
static int countPref(TrieNode root, string pref)
{
TrieNode node = root;
foreach(char ch in pref)
{
int idx = ch - 'a';
// Prefix not present in the trie.
if (node.child[idx] == null) {
return 0;
}
node = node.child[idx];
}
// The stored count equals the number of
// words having this prefix.
return node.cnt;
}
static List<int> prefCount(List<string> s,
List<string> q)
{
// Create the root of the trie.
TrieNode root = new TrieNode();
// Insert all words into the trie.
foreach(string word in s) { insert(root, word); }
List<int> res = new List<int>();
// Answer each query independently.
foreach(string pref in q)
{
res.Add(countPref(root, pref));
}
return res;
}
// Driver code
static void Main()
{
List<string> s = new List<string>{
"abracadabra", "geeksforgeeks", "abracadabra",
"geeks", "geeksthrill"
};
List<string> q = new List<string>{ "abr", "geeks",
"ge", "gar" };
List<int> res = prefCount(s, q);
Console.Write("[");
for (int i = 0; i < res.Count; i++) {
Console.Write(res[i]);
if (i != res.Count - 1) {
Console.Write(", ");
}
}
Console.Write("]");
}
}
// Trie node representing a single character.
class TrieNode {
constructor()
{
// Number of words having the prefix represented
// by the path from root to this node.
this.cnt = 0;
// Pointers to child nodes for characters 'a' to
// 'z'.
this.child = new Array(26).fill(null);
}
}
// Inserts a word into the trie and updates
// the prefix count at each visited node.
function insert(root, word)
{
let node = root;
for (let ch of word) {
let idx = ch.charCodeAt(0) - "a".charCodeAt(0);
// Create a new node if the path does not exist.
if (node.child[idx] === null) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
// Increment the count of words passing
// through this prefix node.
node.cnt++;
}
}
// Returns the number of words that start
// with the given prefix.
function countPref(root, pref)
{
let node = root;
for (let ch of pref) {
let idx = ch.charCodeAt(0) - "a".charCodeAt(0);
// Prefix not present in the trie.
if (node.child[idx] === null) {
return 0;
}
node = node.child[idx];
}
// The stored count equals the number of
// words having this prefix.
return node.cnt;
}
function prefCount(s, q)
{
// Create the root of the trie.
let root = new TrieNode();
// Insert all words into the trie.
for (let word of s) {
insert(root, word);
}
let res = [];
// Answer each query independently.
for (let pref of q) {
res.push(countPref(root, pref));
}
return res;
}
// Driver code
let s = [
"abracadabra", "geeksforgeeks", "abracadabra", "geeks",
"geeksthrill"
];
let q = [ "abr", "geeks", "ge", "gar" ];
let res = prefCount(s, q);
process.stdout.write("[");
for (let i = 0; i < res.length; i++) {
process.stdout.write(res[i].toString());
if (i !== res.length - 1) {
process.stdout.write(", ");
}
}
process.stdout.write("]");
Output
[2, 3, 3, 0]