简体   繁体   中英

Leetcode Python 208. Implement Trie (Prefix Tree)

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.

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

Here's another solution using the 'defaultdictionary' from the collections module to utilize recursion in the 'insert' function too.

Credit: https://leetcode.com/problems/implement-trie-prefix-tree/discuss/631957/python-elegant-solution-no-nested-dictionaries

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)
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 becase 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 becasue 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]])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM