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.

Try It Yourselfredirect icon

Table of Content

[Naive Approach] Check Every String Pair - O(|s1| * |s2| * L) Time O(1) Space

The idea is to check every string of s2 against every string of s1. For each pair of strings, we verify whether the string from s2 occurs as a prefix or as a suffix of the string from s1. If either condition is satisfied for at least one string in s1, we count that string from s2 in 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 True

Checks 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 True

def 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 count

Driver 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 s1 into 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 from s1. Then, for each string in s2, 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:

#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 True

def 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 res

Driver 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)