Given an array of strings arr[] and some queries where each query consists of a string str and an integer k. The task is to find the count of strings in arr[] whose prefix of length k matches with the k length prefix of str.
Examples:
Input: arr[] = ["abba", "abbb", "abbc", "abbd", "abaa", "abca"], str = "abbg", k = 3
Output: 4
"abba", "abbb", "abbc" and "abbd" are the matching strings.Input: arr[] = ["geeks", "geeksforgeeks", "forgeeks"], str = "geeks", k = 2
Output: 2
Table of Content
[Naive Approach] Using Direct Prefix Comparison - O(n * k) Time and O(1) Space
We compare the first
kcharacters of the given string with the firstkcharacters of every string in the array. If they match, we count that string.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int PrefixMatchCount(vector<string>& arr, string str, int k) {
// If input string is smaller than k, no match possible
if (str.length() < k)
return 0;
// Initialize count of matching strings
int count = 0;
// Iterate through each string in the vector
for (const string& s : arr) {
// Skip strings smaller than k
if (s.length() < k)
continue;
// Compare first k characters
if (s.substr(0, k) == str.substr(0, k)) {
// Increment if match found
count++;
}
}
// Return final count
return count;
}
int main() {
vector<string> arr = { "abba", "abbb", "abbc", "abbd", "abaa", "abca" };
string str = "abbg";
int k = 3;
cout << PrefixMatchCount(arr, str, k) << endl;
return 0;
}
import java.util.*;
class GFG {
static int PrefixMatchCount(String[] arr, String str, int k) {
// If input string is smaller than k, no match possible
if (str.length() < k)
return 0;
// Initialize count of matching strings
int count = 0;
// Iterate through each string in the array
for (String s : arr) {
// Skip strings smaller than k
if (s.length() < k)
continue;
// Compare first k characters
if (s.substring(0, k).equals(str.substring(0, k))) {
// Increment if match found
count++;
}
}
// Return final count
return count;
}
public static void main(String[] args) {
String[] arr = {
"abba", "abbb", "abbc", "abbd", "abaa", "abca"
};
String str = "abbg";
int k = 3;
System.out.println(PrefixMatchCount(arr, str, k));
}
}
def PrefixMatchCount(arr, string, k):
# If input string is smaller than k, no match possible
if len(string) < k:
return 0
# Initialize count of matching strings
count = 0
# Iterate through each string in the vector
for s in arr:
# Skip strings smaller than k
if len(s) < k:
continue
# Compare first k characters
if s[:k] == string[:k]:
# Increment if match found
count += 1
# Return final count
return count
arr = ["abba", "abbb", "abbc", "abbd", "abaa", "abca"]
string = "abbg"
k = 3
print(PrefixMatchCount(arr, string, k))
using System;
using System.Collections.Generic;
class GFG {
static int PrefixMatchCount(List<string> arr, string str, int k) {
// If input string is smaller than k, no match possible
if (str.Length < k)
return 0;
// Initialize count of matching strings
int count = 0;
// Iterate through each string in the vector
foreach (string s in arr) {
// Skip strings smaller than k
if (s.Length < k)
continue;
// Compare first k characters
if (s.Substring(0, k).Equals(str.Substring(0, k))) {
// Increment if match found
count++;
}
}
// Return final count
return count;
}
static void Main() {
List<string> arr = new List<string> {
"abba", "abbb", "abbc", "abbd", "abaa", "abca"
};
string str = "abbg";
int k = 3;
Console.WriteLine(PrefixMatchCount(arr, str, k));
}
}
function PrefixMatchCount(arr, str, k) {
// If input string is smaller than k → no match possible
if (str.length < k)
return 0;
// Initialize count of matching strings
let count = 0;
// Iterate through each string in the vector
for (let s of arr) {
// Skip strings smaller than k
if (s.length < k)
continue;
// Compare first k characters
if (s.substring(0, k) === str.substring(0, k)) {
// Increment if match found
count++;
}
}
// Return final count
return count;
}
// Driver code
let arr = ["abba", "abbb", "abbc", "abbd", "abaa", "abca"];
let str = "abbg";
let k = 3;
console.log(PrefixMatchCount(arr, str, k));
Output
4
[Optimal Approach] Using Trie (Prefix Counting) - O(n * L + k) Time and O(n * L) Space
We use a Trie to store all strings and maintain frequency at each node. While inserting, we increment the frequency for every prefix. Then for a given string, we traverse up to length
kand return the frequency stored at that node, which represents how many strings share that prefix.
- Create a Trie node structure with 26 children and frequency
- Insert all strings into the Trie. While inserting, increment frequency at each node
- Start traversing the given string from root, move character by character in Trie. If path breaks, return 0
- When length
kis reached, return stored frequency
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Trie node (considering only lowercase alphabets)
struct TrieNode {
TrieNode* arr[26];
int freq;
// Constructor to initialize node
TrieNode() {
freq = 0;
for (int i = 0; i < 26; i++)
arr[i] = nullptr;
}
};
// Function to insert a node in the trie
TrieNode* insert(string s, TrieNode* root)
{
int in;
TrieNode* cur = root;
for (int i = 0; i < s.length(); i++) {
in = s[i] - 'a';
// If there is no node created then create one
if (cur->arr[in] == nullptr)
cur->arr[in] = new TrieNode();
// Increase the frequency of the node
cur->arr[in]->freq++;
// Move to the next node
cur = cur->arr[in];
}
// Return the updated root
return root;
}
// Function to return the count of strings
// whose prefix of length k matches with the
// k length prefix of the given string
int kLengthPref(vector<string> arr, int k, string str)
{
// Create root of trie
TrieNode* root = new TrieNode();
// Insert all strings into trie
for (int i = 0; i < arr.size(); i++)
root = insert(arr[i], root);
int in, count = 0;
TrieNode* cur = root;
// Traverse the string
for (int i = 0; i < str.length(); i++) {
in = str[i] - 'a';
// If there is no node then return 0
if (cur->arr[in] == nullptr)
return 0;
// Else traverse to the required node
cur = cur->arr[in];
count++;
// Return the required count
if (count == k)
return cur->freq;
}
return 0;
}
// Driver code
int main()
{
vector<string> arr = { "abba", "abbb", "abbc", "abbd", "abaa", "abca" };
// Query 1
cout << kLengthPref(arr, 3, "abbg") << endl;
return 0;
}
import java.util.*;
// Trie node (considering only lowercase alphabets)
class TrieNode {
TrieNode[] arr = new TrieNode[26];
int freq;
// Constructor to initialize node
TrieNode() {
freq = 0;
for (int i = 0; i < 26; i++)
arr[i] = null;
}
}
class GFG {
// Function to insert a node in the trie
static TrieNode insert(String s, TrieNode root)
{
int in;
TrieNode cur = root;
for (int i = 0; i < s.length(); i++) {
in = s.charAt(i) - 'a';
// If there is no node created then create one
if (cur.arr[in] == null)
cur.arr[in] = new TrieNode();
// Increase the frequency of the node
cur.arr[in].freq++;
// Move to the next node
cur = cur.arr[in];
}
// Return the updated root
return root;
}
// Function to return the count of strings
// whose prefix of length k matches with the
// k length prefix of the given string
static int kLengthPref(String[] arr, int k, String str)
{
// Create root of trie
TrieNode root = new TrieNode();
// Insert all strings into trie
for (int i = 0; i < arr.length; i++)
root = insert(arr[i], root);
int in, count = 0;
TrieNode cur = root;
// Traverse the string
for (int i = 0; i < str.length(); i++) {
in = str.charAt(i) - 'a';
// If there is no node then return 0
if (cur.arr[in] == null)
return 0;
// Else traverse to the required node
cur = cur.arr[in];
count++;
// Return the required count
if (count == k)
return cur.freq;
}
return 0;
}
// Driver code
public static void main(String[] args)
{
String[] arr = {
"abba", "abbb", "abbc", "abbd", "abaa", "abca"
};
// Query 1
System.out.println(kLengthPref(arr, 3, "abbg"));
}
}
# Trie node (considering only lowercase alphabets)
class TrieNode:
# Constructor to initialize node
def __init__(self):
self.arr = [None] * 26
self.freq = 0
# Function to insert a node in the trie
def insert(s, root):
cur = root
for i in range(len(s)):
idx = ord(s[i]) - ord('a')
# If there is no node created then create one
if cur.arr[idx] is None:
cur.arr[idx] = TrieNode()
# Increase the frequency of the node
cur.arr[idx].freq += 1
# Move to the next node
cur = cur.arr[idx]
# Return the updated root
return root
# Function to return the count of strings
# whose prefix of length k matches with the
# k length prefix of the given string
def kLengthPref(arr, k, string):
# Create root of trie
root = TrieNode()
# Insert all strings into trie
for i in range(len(arr)):
root = insert(arr[i], root)
count = 0
cur = root
# Traverse the string
for i in range(len(string)):
idx = ord(string[i]) - ord('a')
# If there is no node then return 0
if cur.arr[idx] is None:
return 0
# Else traverse to the required node
cur = cur.arr[idx]
count += 1
# Return the required count
if count == k:
return cur.freq
return 0
# Driver code
arr = ["abba", "abbb", "abbc", "abbd", "abaa", "abca"]
# Query 1
print(kLengthPref(arr, 3, "abbg"))
using System;
using System.Collections.Generic;
// Trie node (considering only lowercase alphabets)
class TrieNode {
public TrieNode[] arr = new TrieNode[26];
public int freq;
// Constructor to initialize node
public TrieNode() {
freq = 0;
for (int i = 0; i < 26; i++)
arr[i] = null;
}
}
class GFG {
// Function to insert a node in the trie
static TrieNode insert(string s, TrieNode root)
{
int inx;
TrieNode cur = root;
for (int i = 0; i < s.Length; i++) {
inx = s[i] - 'a';
// If there is no node created then create one
if (cur.arr[inx] == null)
cur.arr[inx] = new TrieNode();
// Increase the frequency of the node
cur.arr[inx].freq++;
// Move to the next node
cur = cur.arr[inx];
}
// Return the updated root
return root;
}
// Function to return the count of strings
// whose prefix of length k matches with the
// k length prefix of the given string
static int kLengthPref(List<string> arr, int k, string str)
{
// Create root of trie
TrieNode root = new TrieNode();
// Insert all strings into trie
for (int i = 0; i < arr.Count; i++)
root = insert(arr[i], root);
int inx, count = 0;
TrieNode cur = root;
// Traverse the string
for (int i = 0; i < str.Length; i++) {
inx = str[i] - 'a';
// If there is no node then return 0
if (cur.arr[inx] == null)
return 0;
// Else traverse to the required node
cur = cur.arr[inx];
count++;
// Return the required count
if (count == k)
return cur.freq;
}
return 0;
}
// Driver code
static void Main()
{
List<string> arr = new List<string> {
"abba", "abbb", "abbc", "abbd", "abaa", "abca"
};
// Query 1
Console.WriteLine(kLengthPref(arr, 3, "abbg"));
}
}
// Trie node (considering only lowercase alphabets)
class TrieNode {
// Constructor to initialize node
constructor() {
this.arr = new Array(26).fill(null);
this.freq = 0;
}
}
// Function to insert a node in the trie
function insert(s, root)
{
let cur = root;
for (let i = 0; i < s.length; i++) {
let idx = s.charCodeAt(i) - 'a'.charCodeAt(0);
// If there is no node created then create one
if (cur.arr[idx] === null)
cur.arr[idx] = new TrieNode();
// Increase the frequency of the node
cur.arr[idx].freq++;
// Move to the next node
cur = cur.arr[idx];
}
// Return the updated root
return root;
}
// Function to return the count of strings
// whose prefix of length k matches with the
// k length prefix of the given string
function kLengthPref(arr, k, str)
{
// Create root of trie
let root = new TrieNode();
// Insert all strings into trie
for (let i = 0; i < arr.length; i++)
root = insert(arr[i], root);
let count = 0;
let cur = root;
// Traverse the string
for (let i = 0; i < str.length; i++) {
let idx = str.charCodeAt(i) - 'a'.charCodeAt(0);
// If there is no node then return 0
if (cur.arr[idx] === null)
return 0;
// Else traverse to the required node
cur = cur.arr[idx];
count++;
// Return the required count
if (count === k)
return cur.freq;
}
return 0;
}
// Driver code
let arr = ["abba", "abbb", "abbc", "abbd", "abaa", "abca"];
// Query 1
console.log(kLengthPref(arr, 3, "abbg"));
Output
4