Counting common prefix/suffix strings in two lists

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 Yourself
redirect icon

[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 <iostream>
#include <string>
#include <vector>
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<string> &s1, vector<string> &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));

Output
4

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:

  • Build a Trie by inserting every string from s1, so that every traversable path from the root represents a prefix of some string in s1.
  • To support suffix matching, also insert the reversed form of every string from s1 into the same Trie.
  • For each string str in s2, check whether str can be completely traversed in the Trie. If yes, it is a prefix of at least one string in s1.
  • Also reverse str and check whether the reversed string can be traversed in the Trie. If yes, str is a suffix of at least one string in s1.
  • Count every string in s2 for which either the prefix check or the suffix check succeeds.
C++
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
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<string> &s1, vector<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 (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<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 {
    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));

Output
4

Time Complexity: O((n + m) * L)
Auxiliary Space: O(n * L)

Comment