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)
returns true if str1 is both a prefix and a suffix of str2, and false otherwise.
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: 4
Explanation: 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: 2
Explanation: 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.
Example 3:
Input: words = ["abab","ab"]
Output: 0
Explanation: In this example, the only valid index pair is i = 0 and j = 1, and isPrefixAndSuffix("abab", "ab") is false.
Therefore, the answer is 0.
Constraints:
1 <= words.length <= 10^5
1 <= words[i].length <= 10^5
words[i] consists only of lowercase English letters.
The sum of the lengths of all words[i] does not exceed 5 * 10^5.
Solution
3042 is just an easier version with looser constrains. For this problem I do with trie tree.
My thoughts:
Use a trie tree to store all the words, and then search and add the is_end
to the final result => according to the description, i
has to be: i < j
, and suffix is not just the reversed prefix
=> build a prefix trie tree and a suffix prefix tree => what if a word is a prefix of word a
and a suffix of word b
?
=> instead of using boolean is_end
, use a set to store the word => what if a word is a prefix of 2 same words? like [a, aa, aa]
?
=> instead of using a set, use a hash map => memory limit error
=> pass a word_mapping
to the object, store the index of the word instead of the word => TLE
Code
class TrieNode:
def __init__(self) -> None:
self.child = {}
self.is_end = {}
class TrieTree:
def __init__(self, word_mapping: dict, is_reversed=False) -> None:
self.root = TrieNode()
self.is_reversed = is_reversed
self.word_mapping = word_mapping
def insert(self, word: str) -> None:
node = self.root
for each_char in word:
if each_char not in node.child:
node.child[each_char] = TrieNode()
node = node.child[each_char]
word_key = self.word_mapping[word if not self.is_reversed else word[::-1]]
node.is_end[word_key] = node.is_end.get(word_key, 0) + 1
def search(self, word: str) -> dict:
node = self.root
for each_char in word:
if each_char not in node.child:
return {}
node = node.child[each_char]
return node.is_end
class Solution:
def countPrefixSuffixPairs(self, words: List[str]) -> int:
word_mapping = {words[i]: i for i in range(len(words))}
prefix_tree = TrieTree(word_mapping)
suffix_tree = TrieTree(word_mapping, is_reversed=True)
res = 0
for each_word in words[::-1]:
common_keys = prefix_tree.search(each_word).keys() & suffix_tree.search(each_word[::-1]).keys()
for each_key in common_keys:
res += min(prefix_tree.search(each_word)[each_key], suffix_tree.search(each_word[::-1])[each_key])
prefix_tree.insert(each_word)
suffix_tree.insert(each_word[::-1])
return res