trie
string
]
Leetcode 0745. Prefix and Suffix Search
Problem statement
https://leetcode.com/problems/prefix-and-suffix-search/
Solution 1
Let n be number of words, L be maximum length of word. One of the cool ways to solve this problem is the following: imagine, we have word apple, then what we need to find is substring suffix + # + prefix in string apple#apple. Now, quick way to find substring is for example create Trie with all suffixes of apple#apple, which include #.
Complexity
It is O(nL^2) time and space for init: for each word we need O(L^2) processing time. For f we need O(L) time and O(1) space, because we just traverse through tree. So, final complexity is O(nL^2 + QL), where Q is number of queries.
Code
class TrieNode:
def __init__(self):
self.children = {}
self.index = 0
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word, index): #None
root = self.root
root.index = index
for symbol in word:
root = root.children.setdefault(symbol, TrieNode())
root.index = index
def startsWith(self, word):
root = self.root
for symbol in word:
if symbol not in root.children:
return -1
root = root.children[symbol]
return root.index
class WordFilter:
def __init__(self, words):
self.trie = Trie()
self.words = {}
for index, word in enumerate(words):
long = word + "#" + word
for i in range(len(word)):
self.trie.insert(long[i:], index)
def f(self, prefix, suffix):
return self.trie.startsWith(suffix + "#" + prefix)
Solution 2
Finally, there is again solution with O(nL^3) time complexity, but without Tries at all: we just generate for each word all O(L^2) possible prefix/suffix pairs and put them into dictionary. It is working the best in practice, even though complexity is higher. This is because L is quite small and trie is quite heavy data structure with all connections, whereas here we keep only strings.
Complexity
Time is O(nL^3 + QL), space is O(nL^3).
Code
class WordFilter:
def __init__(self, words):
self.d = {}
for i, word in enumerate(words):
for p, s in product(range(len(word) + 1), repeat=2):
self.d[word[:p], word[s:]] = i
def f(self, prefix, suffix):
return self.d.get((prefix, suffix), -1)