Counting common prefix/suffix strings in two lists (original) (raw)
Last Updated : 4 Jun, 2026
Given two arrays of strings, **s1[] and **s2[], count the number of strings in s2[] that occur as either a **prefix or a **suffix of at least one string in s1[]. Return the **total count.
**Examples:
**Input: s1 = ["cat", "catanddog", "lion"], s2 = ["cat", "dog", "rat"]
**Output: 2
**Explanation:
"cat" from s2 is a prefix of "catanddog" in s1.
"dog" from s2 is a suffix of "catanddog" in s1.
"rat" is neither a prefix nor a suffix of any string in s1.
Therefore, the count is 2.**Input: s1 = ["jrjiml", "tchetn", "ucrhye", "ynayhy", "cuhffd", "cvgpoiu", "znyadv"]
s2 = ["jr", "ml", "cvgpoi", "gpoiu", "wnmkmluc", "geheqe", "uglxagyl", "uyxdroj"]
**Output: 4
**Explanation:
"jr" is a prefix of "jrjiml" in s1.
"ml" is a suffix of "jrjiml" in s1.
"cvgpoi" is a prefix of "cvgpoiu" in s1.
"gpoiu" is a suffix of "cvgpoiu" in s1.
The remaining strings in s2 are neither prefixes nor suffixes of any string in s1.
Therefore, the count is 4.
Table of Content
- [Naive Approach] Check Every String Pair - O(|s1| * |s2| * L) Time O(1) Space
- [Expected Approach] Trie-Based Prefix and Suffix Matching - O((n + m) * L) Time O(n * L) Space
[Naive Approach] Check Every String Pair - O(|s1| * |s2| * L) Time O(1) Space
The idea is to check every string of
s2against every string ofs1. For each pair of strings, we verify whether the string froms2occurs as a prefix or as a suffix of the string froms1. If either condition is satisfied for at least one string ins1, we count that string froms2in the answer.
C++ `
#include #include #include using namespace std;
// Checks whether pat is a prefix of string bool isPrefix(string &str, string &pat) { int n = str.length(); int m = pat.length();
if (m > n)
{
return false;
}
for (int i = 0; i < m; i++)
{
if (str[i] != pat[i])
{
return false;
}
}
return true;}
// Checks whether pat is a suffix of str bool isSuffix(string &str, string &pat) { int n = str.length(); int m = pat.length();
if (m > n)
{
return false;
}
for (int i = 0; i < m; i++)
{
if (str[n - m + i] != pat[i])
{
return false;
}
}
return true;}
int countPrefixSuffix(vector &s1, vector &s2) {
int count = 0;
// Check every string pair
for (string &pat : s2)
{
bool found = false;
for (string &str : s1)
{
if (isPrefix(str, pat) || isSuffix(str, pat))
{
found = true;
break;
}
}
if (found)
{
count++;
}
}
return count;}
// Driver Code int main() {
vector<string> s1 = {"jrjiml", "tchetn", "ucrhye", "ynayhy", "cuhffd", "cvgpoiu", "znyadv"};
vector<string> s2 = {"jr", "ml", "cvgpoi", "gpoiu", "wnmkmluc", "geheqe", "uglxagyl", "uyxdroj"};
cout << countPrefixSuffix(s1, s2) << endl;
return 0;}
Java
import java.util.*;
class GfG {
// Checks whether pat is a prefix of string
static boolean isPrefix(String str, String pat)
{
int n = str.length();
int m = pat.length();
if (m > n) {
return false;
}
for (int i = 0; i < m; i++) {
if (str.charAt(i) != pat.charAt(i)) {
return false;
}
}
return true;
}
// Checks whether pat is a suffix of str
static boolean isSuffix(String str, String pat)
{
int n = str.length();
int m = pat.length();
if (m > n) {
return false;
}
for (int i = 0; i < m; i++) {
if (str.charAt(n - m + i) != pat.charAt(i)) {
return false;
}
}
return true;
}
static int countPrefixSuffix(String[] s1, String[] s2)
{
int count = 0;
// Check every string pair
for (String pat : s2) {
boolean found = false;
for (String str : s1) {
if (isPrefix(str, pat)
|| isSuffix(str, pat)) {
found = true;
break;
}
}
if (found) {
count++;
}
}
return count;
}
// Driver Code
public static void main(String[] args)
{
String[] s1
= { "jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv" };
String[] s2 = { "jr", "ml", "cvgpoi",
"gpoiu", "wnmkmluc", "geheqe",
"uglxagyl", "uyxdroj" };
System.out.println(countPrefixSuffix(s1, s2));
}}
Python
Checks whether pat is a prefix of string
def isPrefix(string, pat): n = len(string) m = len(pat)
if m > n:
return False
for i in range(m):
if string[i] != pat[i]:
return False
return TrueChecks whether pat is a suffix of str
def isSuffix(string, pat): n = len(string) m = len(pat)
if m > n:
return False
for i in range(m):
if string[n - m + i] != pat[i]:
return False
return Truedef countPrefixSuffix(s1, s2):
count = 0
# Check every string pair
for pat in s2:
found = False
for string in s1:
if isPrefix(string, pat) or isSuffix(string, pat):
found = True
break
if found:
count += 1
return countDriver Code
if name == "main":
s1 = ["jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv"]
s2 = ["jr", "ml", "cvgpoi", "gpoiu",
"wnmkmluc", "geheqe", "uglxagyl", "uyxdroj"]
print(countPrefixSuffix(s1, s2))C#
using System; using System.Collections.Generic;
class GfG { // Checks whether pat is a prefix of string static bool isPrefix(string str, string pat) { int n = str.Length; int m = pat.Length;
if (m > n) {
return false;
}
for (int i = 0; i < m; i++) {
if (str[i] != pat[i]) {
return false;
}
}
return true;
}
// Checks whether pat is a suffix of str
static bool isSuffix(string str, string pat)
{
int n = str.Length;
int m = pat.Length;
if (m > n) {
return false;
}
for (int i = 0; i < m; i++) {
if (str[n - m + i] != pat[i]) {
return false;
}
}
return true;
}
static int countPrefixSuffix(List<string> s1,
List<string> s2)
{
int count = 0;
// Check every string pair
foreach(string pat in s2)
{
bool found = false;
foreach(string str in s1)
{
if (isPrefix(str, pat)
|| isSuffix(str, pat)) {
found = true;
break;
}
}
if (found) {
count++;
}
}
return count;
}
// Driver Code
static void Main()
{
List<string> s1 = new List<string>{
"jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv"
};
List<string> s2 = new List<string>{
"jr", "ml", "cvgpoi", "gpoiu",
"wnmkmluc", "geheqe", "uglxagyl", "uyxdroj"
};
Console.WriteLine(countPrefixSuffix(s1, s2));
}}
JavaScript
// Checks whether pat is a prefix of string function isPrefix(str, pat) { let n = str.length; let m = pat.length;
if (m > n) {
return false;
}
for (let i = 0; i < m; i++) {
if (str[i] !== pat[i]) {
return false;
}
}
return true;}
// Checks whether pat is a suffix of str function isSuffix(str, pat) { let n = str.length; let m = pat.length;
if (m > n) {
return false;
}
for (let i = 0; i < m; i++) {
if (str[n - m + i] !== pat[i]) {
return false;
}
}
return true;}
function countPrefixSuffix(s1, s2) {
let count = 0;
// Check every string pair
for (let pat of s2) {
let found = false;
for (let str of s1) {
if (isPrefix(str, pat) || isSuffix(str, pat)) {
found = true;
break;
}
}
if (found) {
count++;
}
}
return count;}
// Driver Code let s1 = [ "jrjiml", "tchetn", "ucrhye", "ynayhy", "cuhffd", "cvgpoiu", "znyadv" ];
let s2 = [ "jr", "ml", "cvgpoi", "gpoiu", "wnmkmluc", "geheqe", "uglxagyl", "uyxdroj" ];
console.log(countPrefixSuffix(s1, s2));
`
**Time Complexity: O(|s1| * |s2| * L)
**Auxiliary Space: O(1)
[Expected Approach] Trie-Based Prefix and Suffix Matching - O((n + m) * L) Time O(n * L) Space
The idea is to use a Trie to efficiently store prefixes of strings. We insert every string from
s1into the Trie so that any traversable path represents a prefix of some string. To handle suffixes, we also insert the reversed form of every string froms1. Then, for each string ins2, we check whether it can be traversed in the Trie (prefix check) or whether its reversed form can be traversed in the Trie (suffix check). If either check succeeds, the string contributes to the answer.
**Working of the Approach:
- Build a Trie by inserting every string from
s1, so that every traversable path from the root represents a prefix of some string ins1. - To support suffix matching, also insert the reversed form of every string from
s1into the same Trie. - For each string
strins2, check whetherstrcan be completely traversed in the Trie. If yes, it is a prefix of at least one string ins1. - Also reverse
strand check whether the reversed string can be traversed in the Trie. If yes,stris a suffix of at least one string ins1. - Count every string in
s2for which either the prefix check or the suffix check succeeds. C++ `
#include #include #include #include using namespace std;
class TrieNode { public: TrieNode *child[26];
TrieNode()
{
// Initialize all child pointers as null
for (int i = 0; i < 26; i++)
{
child[i] = nullptr;
}
}};
// Inserts a string into the Trie void add(TrieNode *root, const string &s) { TrieNode *node = root;
for (char ch : s)
{
int idx = ch - 'a';
// Create a new node if the current character
// is not already present in the Trie
if (!node->child[idx])
{
node->child[idx] = new TrieNode();
}
node = node->child[idx];
}}
// Returns true if all characters of the string // can be traversed in the Trie bool find(TrieNode *root, const string &s) { TrieNode *node = root;
for (char ch : s)
{
int idx = ch - 'a';
if (!node->child[idx])
{
return false;
}
node = node->child[idx];
}
return true;}
int countPrefixSuffix(vector &s1, vector &s2) { TrieNode *root = new TrieNode();
// Insert every string from s1.
// Any path in the Trie represents a prefix of some string.
// Also insert the reversed string so that suffix checks
// can be converted into prefix checks on reversed strings.
for (const string &str : s1)
{
add(root, str);
string rev = str;
reverse(rev.begin(), rev.end());
add(root, rev);
}
int res = 0;
for (const string &str : s2)
{
string rev = str;
reverse(rev.begin(), rev.end());
// If 'str' exists as a Trie path, it is a prefix
// of at least one string in s1.
//
// If reversed(str) exists as a Trie path, then
// 'str' is a suffix of at least one string in s1.
if (find(root, str) || find(root, rev))
{
res++;
}
}
return res;}
// Driver Code int main() { vector s1 = {"jrjiml", "tchetn", "ucrhye", "ynayhy", "cuhffd", "cvgpoiu", "znyadv"};
vector<string> s2 = {"jr", "ml", "cvgpoi", "gpoiu", "wnmkmluc", "geheqe", "uglxagyl", "uyxdroj"};
cout << countPrefixSuffix(s1, s2) << endl;
return 0;}
Java
import java.util.*;
class GfG { class TrieNode { TrieNode[] child;
TrieNode()
{
// Initialize all child pointers as null
child = new TrieNode[26];
}
}
// Inserts a string into the Trie
private void add(TrieNode root, String s)
{
TrieNode node = root;
for (char ch : s.toCharArray()) {
int idx = ch - 'a';
// Create a new node if the current
// character is not already present in the
// Trie
if (node.child[idx] == null) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
}
}
// Returns true if all characters of the string
// can be traversed in the Trie
private boolean find(TrieNode root, String s)
{
TrieNode node = root;
for (char ch : s.toCharArray()) {
int idx = ch - 'a';
if (node.child[idx] == null) {
return false;
}
node = node.child[idx];
}
return true;
}
public int countPrefixSuffix(String[] s1, String[] s2)
{
TrieNode root = new TrieNode();
// Insert every string from s1.
// Any path in the Trie represents a prefix of
// some string. Also insert the reversed string
// so that suffix checks can be converted into
// prefix checks on reversed strings.
for (String str : s1) {
add(root, str);
String rev = new StringBuilder(str)
.reverse()
.toString();
add(root, rev);
}
int res = 0;
for (String str : s2) {
String rev = new StringBuilder(str)
.reverse()
.toString();
// If 'str' exists as a Trie path, it is a
// prefix of at least one string in s1.
//
// If reversed(str) exists as a Trie path,
// then 'str' is a suffix of at least one
// string in s1.
if (find(root, str) || find(root, rev)) {
res++;
}
}
return res;
}
// Driver Code
public static void main(String[] args)
{
String[] s1
= { "jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv" };
String[] s2 = { "jr", "ml", "cvgpoi",
"gpoiu", "wnmkmluc", "geheqe",
"uglxagyl", "uyxdroj" };
GfG obj = new GfG();
System.out.println(obj.countPrefixSuffix(s1, s2));
}}
Python
class TrieNode: def init(self): self.child = [None] * 26
Inserts a string into the Trie
def add(root, s): node = root
for ch in s:
idx = ord(ch) - ord('a')
if not node.child[idx]:
node.child[idx] = TrieNode()
node = node.child[idx]Returns true if all characters of the string
can be traversed in the Trie
def find(root, s): node = root
for ch in s:
idx = ord(ch) - ord('a')
if not node.child[idx]:
return False
node = node.child[idx]
return Truedef countPrefixSuffix(s1, s2): root = TrieNode()
for str in s1:
add(root, str)
rev = str[::-1]
add(root, rev)
res = 0
for str in s2:
rev = str[::-1]
if find(root, str) or find(root, rev):
res += 1
return resDriver Code
if name == "main":
s1 = ["jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv"]
s2 = ["jr", "ml", "cvgpoi", "gpoiu",
"wnmkmluc", "geheqe",
"uglxagyl", "uyxdroj"]
print(countPrefixSuffix(s1, s2))C#
using System;
class TrieNode { public TrieNode[] child;
public TrieNode()
{
// Initialize all child pointers as null
child = new TrieNode[26];
}}
class GfG { // Inserts a string into the Trie static void add(TrieNode root, string s) { TrieNode node = root;
foreach(char ch in s)
{
int idx = ch - 'a';
// Create a new node if the current character
// is not already present in the Trie
if (node.child[idx] == null) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
}
}
// Returns true if all characters of the string
// can be traversed in the Trie
static bool find(TrieNode root, string s)
{
TrieNode node = root;
foreach(char ch in s)
{
int idx = ch - 'a';
if (node.child[idx] == null) {
return false;
}
node = node.child[idx];
}
return true;
}
static int countPrefixSuffix(string[] s1, string[] s2)
{
TrieNode root = new TrieNode();
// Insert every string from s1.
// Any path in the Trie represents a prefix of some
// string. Also insert the reversed string so that
// suffix checks can be converted into prefix checks
// on reversed strings.
foreach(string str in s1)
{
add(root, str);
char[] arr = str.ToCharArray();
Array.Reverse(arr);
string rev = new string(arr);
add(root, rev);
}
int res = 0;
foreach(string str in s2)
{
char[] arr = str.ToCharArray();
Array.Reverse(arr);
string rev = new string(arr);
// If 'str' exists as a Trie path, it is a
// prefix of at least one string in s1.
//
// If reversed(str) exists as a Trie path, then
// 'str' is a suffix of at least one string in
// s1.
if (find(root, str) || find(root, rev)) {
res++;
}
}
return res;
}
// Driver Code
static void Main()
{
string[] s1
= { "jrjiml", "tchetn", "ucrhye", "ynayhy",
"cuhffd", "cvgpoiu", "znyadv" };
string[] s2 = { "jr", "ml", "cvgpoi",
"gpoiu", "wnmkmluc", "geheqe",
"uglxagyl", "uyxdroj" };
Console.WriteLine(countPrefixSuffix(s1, s2));
}}
JavaScript
class TrieNode { constructor() { // Initialize all child pointers as null this.child = new Array(26).fill(null); } }
// Inserts a string into the Trie function add(root, s) { let node = root;
for (let ch of s) {
let idx = ch.charCodeAt(0) - "a".charCodeAt(0);
// Create a new node if the current character
// is not already present in the Trie
if (!node.child[idx]) {
node.child[idx] = new TrieNode();
}
node = node.child[idx];
}}
// Returns true if all characters of the string // can be traversed in the Trie function find(root, s) { let node = root;
for (let ch of s) {
let idx = ch.charCodeAt(0) - "a".charCodeAt(0);
if (!node.child[idx]) {
return false;
}
node = node.child[idx];
}
return true;}
function countPrefixSuffix(s1, s2) { let root = new TrieNode();
// Insert every string from s1.
// Any path in the Trie represents a prefix of some
// string. Also insert the reversed string so that
// suffix checks can be converted into prefix checks on
// reversed strings.
for (let str of s1) {
add(root, str);
let rev = str.split("").reverse().join("");
add(root, rev);
}
let res = 0;
for (let str of s2) {
let rev = str.split("").reverse().join("");
// If 'str' exists as a Trie path, it is a prefix
// of at least one string in s1.
//
// If reversed(str) exists as a Trie path, then
// 'str' is a suffix of at least one string in s1.
if (find(root, str) || find(root, rev)) {
res++;
}
}
return res;}
// Driver Code let s1 = [ "jrjiml", "tchetn", "ucrhye", "ynayhy", "cuhffd", "cvgpoiu", "znyadv" ];
let s2 = [ "jr", "ml", "cvgpoi", "gpoiu", "wnmkmluc", "geheqe", "uglxagyl", "uyxdroj" ];
console.log(countPrefixSuffix(s1, s2));
`
**Time Complexity: O((n + m) * L)
**Auxiliary Space: O(n * L)