3042. Count Prefix and Suffix Pairs I - Explanation
Description
You are given a 0-indexed string array words.
Let's define a boolean function isPrefixAndSuffix that takes two strings, str1 and str2:
isPrefixAndSuffix(str1, str2)returnstrueifstr1is both a prefix and a suffix ofstr2, andfalseotherwise.
For example, isPrefixAndSuffix("aba", "ababa") is true because "aba" is a prefix of "ababa" and also a suffix, but isPrefixAndSuffix("abc", "abcd") is false.
Return an integer denoting the number of index pairs (i, j) such that i < j, and isPrefixAndSuffix(words[i], words[j]) is true.
Example 1:
Input: words = ["a","aba","ababa","aa"]
Output: 4Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("a", "aba") is true.
i = 0 and j = 2 because isPrefixAndSuffix("a", "ababa") is true.
i = 0 and j = 3 because isPrefixAndSuffix("a", "aa") is true.
i = 1 and j = 2 because isPrefixAndSuffix("aba", "ababa") is true.
Therefore, the answer is 4.
Example 2:
Input: words = ["pa","papa","ma","mama"]
Output: 2Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("pa", "papa") is true.
i = 2 and j = 3 because isPrefixAndSuffix("ma", "mama") is true.
Therefore, the answer is 2.
Constraints:
1 <= words.length <= 501 <= words[i].length <= 10words[i]consists only of lowercase English letters.
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- String Manipulation - Checking prefixes and suffixes of strings using character comparison or built-in methods
- Nested Loops - Iterating through all pairs of elements in an array with O(n^2) complexity
- Trie Data Structure - Understanding how tries store strings and enable efficient prefix lookups (for optimal solution)
1. Brute Force
Intuition
For each pair of indices (i, j) where i < j, we need to check if words[i] is both a prefix and suffix of words[j]. We compare characters at the beginning and end of words[j] with words[i].
Algorithm
- Create a helper function that checks if
s1is both a prefix and suffix ofs2. - First verify
s1is not longer thans2. - Compare
s1character by character with the start ofs2(prefix check). - Compare
s1character by character with the end ofs2(suffix check). - Iterate through all pairs
(i, j)withi < jand count valid prefix-suffix pairs.
class Solution:
def countPrefixSuffixPairs(self, words: List[str]) -> int:
def isPrefixAndSuffix(s1, s2):
if len(s1) > len(s2):
return False
for i in range(len(s1)):
if s1[i] != s2[i]:
return False
j = 0
for i in range(len(s2) - len(s1), len(s2)):
if s1[j] != s2[i]:
return False
j += 1
return True
res = 0
for i in range(len(words)):
for j in range(i + 1, len(words)):
res += isPrefixAndSuffix(words[i], words[j])
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the size of the input array , and is the maximum length of a string.
3. Trie
Intuition
We can use a trie where each node is keyed by a pair of characters: one from the prefix and one from the suffix. By processing words in reverse order and storing them in this combined trie, when we look up a word, we find how many previously seen words have it as both prefix and suffix.
Algorithm
- Create a trie where each edge is labeled by a pair (prefix char, suffix char).
- Process words from the end of the array to the beginning.
- For each word, traverse the trie using pairs of (word[i], word[n-1-i]) and count matches.
- Then insert the word into the trie, incrementing counts at each node.
- Return the total count of matching pairs.
class TrieNode:
def __init__(self):
self.children = {}
self.count = 0
class Trie:
def __init__(self):
self.root = TrieNode()
def add(self, w: str) -> None:
cur = self.root
for c1, c2 in zip(w, reversed(w)):
if (c1, c2) not in cur.children:
cur.children[(c1, c2)] = TrieNode()
cur = cur.children[(c1, c2)]
cur.count += 1
def count(self, w: str) -> int:
cur = self.root
for c1, c2 in zip(w, reversed(w)):
if (c1, c2) not in cur.children:
return 0
cur = cur.children[(c1, c2)]
return cur.count
class Solution:
def countPrefixSuffixPairs(self, words: List[str]) -> int:
res = 0
root = Trie()
for w in reversed(words):
res += root.count(w)
root.add(w)
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the size of the input array , and is the maximum length of a string.
Common Pitfalls
Checking Only Prefix or Only Suffix
The condition requires words[i] to be BOTH a prefix AND a suffix of words[j]. Checking only one condition will give incorrect results.
# Wrong: only checks prefix
if w2.startswith(w1):
res += 1
# Correct: checks both conditions
if w2.startswith(w1) and w2.endswith(w1):
res += 1Forgetting the Length Constraint
A string cannot be a prefix or suffix of a shorter string. Failing to check len(s1) <= len(s2) before comparing can lead to index out of bounds errors or false positives.
Sign in to join the discussion