Reputation: 23
Can someone say what is wrong with my code, it is passing all the test cases except the last one when I downloaded the specific test case both the expected and actual output seems same, the question is https://leetcode.com/problems/implement-trie-prefix-tree/description/
Edit 1: Here is the code:
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.data = None
self.children = {}
self.isWord = False
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
if len(word) == 0:
return
if word[0] not in self.children:
self.children[word[0]] = Trie()
self.insertHelper(word[1:], self.children[word[0]])
else:
self.insertHelper(word[1:], self.children[word[0]])
if len(word) == 1:
self.isWord = True
def insertHelper(self, word, trie):
if len(word) == 0:
return
if word[0] not in trie.children:
trie.children[word[0]] = Trie()
trie.insertHelper(word[1:], trie.children[word[0]])
else:
trie.insertHelper(word[1:], trie.children[word[0]])
if len(word) == 1:
trie.isWord = True
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
if len(word) == 1 and word[0] in self.children and self.isWord:
return True
elif len(word) == 0:
return False
if word[0] in self.children:
return self.searchHelper(word[1:], self.children[word[0]])
else:
return False
def searchHelper(self, word, trie):
if len(word) == 1 and word[0] in trie.children and trie.isWord:
return True
elif len(word) == 0:
return False
if word[0] in trie.children:
return self.searchHelper(word[1:], trie.children[word[0]])
else:
return False
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
if len(prefix) == 0:
return False
if prefix[0] in self.children:
return self.startsWithHelper(prefix[1:], self.children[prefix[0]])
else:
return False
def startsWithHelper(self, prefix, trie):
if len(prefix) == 0:
return True
if prefix[0] in trie.children:
return trie.startsWithHelper(prefix[1:], trie.children[prefix[0]])
else:
return False
Thanks in advance.
Upvotes: 0
Views: 2785
Reputation: 49361
class TrieNode:
def __init__(self):
# each key is a TrieNode
self.keys = {}
self.end = False
class Trie:
def __init__(self):
self.root = TrieNode()
# node=this.root gives error "this" is not defined
def insert(self, word: str, node=None) -> None:
if node == None:
node = self.root
# insertion is a recursive operation
if len(word) == 0:
node.end = True
return
elif word[0] not in node.keys:
node.keys[word[0]] = TrieNode()
self.insert(word[1:], node.keys[word[0]])
# that means key exists
else:
self.insert(word[1:], node.keys[word[0]])
def search(self, word: str, node=None) -> bool:
if node == None:
node = self.root
# node.end=True means we have inserted the word before
if len(word) == 0 and node.end == True:
return True
# if we inserted apple and then search for app we get false because we never inserted app so a-p-p last_p.end is not True
# But startsWith(app) would return True
elif len(word) == 0:
return False
elif word[0] not in node.keys:
return False
else:
# we have to return because api expects us to return bool
return self.search(word[1:], node.keys[word[0]])
def startsWith(self, prefix: str, node=None) -> bool:
if node == None:
node = self.root
if len(prefix) == 0:
return True
elif prefix[0] not in node.keys:
return False
else:
return self.startsWith(prefix[1:], node.keys[prefix[0]])
Upvotes: 0
Reputation: 523
Here's another solution using the 'defaultdictionary' from the collections module to utilize recursion in the 'insert' function too.
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.nodes = collections.defaultdict(Trie)
self.is_word = False
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
if not word:
self.is_word = True
else:
self.nodes[word[0]].insert(word[1:])
def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
if not word:
return self.is_word
if word[0] in self.nodes:
return self.nodes[word[0]].search(word[1:])
return False
def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
if not prefix:
return True
if prefix[0] in self.nodes:
return self.nodes[prefix[0]].startsWith(prefix[1:])
return False
Your Trie object will be instantiated and called as such:
obj = Trie()
obj.insert(word)
param_2 = obj.search(word)
param_3 = obj.startsWith(prefix)
Upvotes: 0
Reputation: 41872
One quirk I noticed is passing an empty prefix into startsWith()
. If this method is modeled on the Python str
method startswith()
, then we expect True
:
>>> "apple".startswith("")
True
>>>
But your Trie returns False
in this situation:
>>> t = Trie()
>>> t.insert("apple")
>>> t.startsWith("")
False
>>>
Below is my rework of your code that I did primarily to understand it but I also found you had redundancies, particularly your Helper functions. This code fixes the quirk mentioned above and is Python 3 specific:
class Trie:
def __init__(self):
self.children = {}
self.isWord = False
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str (or list internally upon recursion)
:rtype: None
"""
if not word:
return
head, *tail = word
if head not in self.children:
self.children[head] = Trie()
trie = self.children[head]
if tail:
trie.insert(tail)
else:
self.isWord = True
def search(self, word):
"""
Returns True if the word is in the trie.
:type word: str (or list internally upon recursion)
:rtype: bool
"""
if not word:
return False
head, *tail = word
if head in self.children:
if not tail and self.isWord:
return True
return self.children[head].search(word[1:])
return False
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str (or list internally upon recursion)
:rtype: bool
"""
if not prefix:
return True
head, *tail = prefix
if head in self.children:
return self.children[head].startsWith(tail)
return False
Upvotes: 2