【问题标题】:Return strings that matches the prefix in a Trie返回与 Trie 中的前缀匹配的字符串
【发布时间】:2018-04-28 14:36:17
【问题描述】:

我设法构造了一个 Trie,现在我想返回与 Trie 中的前缀匹配的字符串,但我在编写搜索函数时遇到了问题。

例如,如果我有一个前缀“aa”,我希望将字符串“aa”和“aac”作为输出。

class Node:
    def __init__(self):
        self.children = [None] * 26
        self.end = False
        self.value = ""

class Trie:
    def __init__(self):
        self.root = Node()

    def add_word(self, key):
        word_length = len(key)
        current = self.root
        for i in range(word_length):
            position = self.ord_char(key[i])

            if current.children[position] is None:
                current.children[position] = Node()
            current = current.children[position]
            current.value = key[i]
        current.end = True

    def ord_char(self,key):
        ord_rep = ord(key) - ord('a')
        return ord_rep

    def prefix_search(self, prefix):
        lst = []
        current = self.root
        prefix_length = len(prefix)
        for c in range(prefix_length):
            c_position = self.ord_char(prefix[c])
            current = current.children[c_position]
            lst.append(current.value)
        #doesnt seem like I'm doing it right

if __name__ == "__main__":
    trie = Trie()
    trie.add_word("aa")
    trie.add_word("aac")
    trie.add_word("b")
    trie.prefix_search("aa")

我想通过搜索功能将字母组合在一起形成最终的字符串,但我想不出更好的方法。

【问题讨论】:

    标签: python trie


    【解决方案1】:

    到目前为止,lst 值只是前缀,拆分为单独的字母,但现在您需要处理在 children 属性中找到的不是 None 的每个节点,以查找所有具有end 设置为 True。每次找到这样一个节点,你就有一个完整的单词。任何节点都可以再次有多个子节点,从而分支出更多要输出的单词。

    您可以使用堆栈来跟踪构建列表所需处理的所有节点,以及到目前为止的前缀。使用该节点的前缀将子节点添加到堆栈中,并逐个处理这些节点(同时将更多子节点添加到堆栈中)。

    请注意,首先,您不需要构建前缀字符列表,您已经将该前缀作为变量。为了达到您的起点,只需遍历前缀本身就更简单了:

    def prefix_search(self, prefix):
        current = self.root
        # get to the starting point
        for c in prefix:
            current = current.children[self.ord_char(c)]
            if current is None:
                # prefix doesn't exist, abort with an empty list
                return []
    
        found = []
        stack = [(current, prefix)]
        while stack:
            current, prefix = stack.pop()
    
            if current.end:
                # this is a complete word, named by prefix
                found.append(prefix)
    
            # add the children to the stack, each with their letter added to the
            # prefix value.
            for child in current.children:
                if child is None:
                    continue
                stack.append((child, prefix + child.value))
    
        return found
    

    对于给定的示例 trie 和前缀,堆栈从节点 'aa' 开始。第一次while stack: 迭代从堆栈中删除该节点,因为该节点将end 设置为true,所以'aa' 被添加到found。该节点只有一个非None 子节点,即c,因此该节点以'aac' 添加到堆栈中。

    然后while循环重复,找到堆栈上的一个元素,看到end被设置所以'aac'被添加到found,并且没有更多的子节点被定位。堆栈保持为空,while 循环结束。

    演示:

    >>> trie = Trie()
    >>> trie.add_word("aa")
    >>> trie.add_word("aac")
    >>> trie.add_word("b")
    >>> trie.prefix_search("aa")
    ['aa', 'aac']
    >>> trie.prefix_search("b")
    ['b']
    >>> trie.add_word('abracadabra')
    >>> trie.add_word('abbreviation')
    >>> trie.add_word('abbreviated')
    >>> trie.add_word('abbrasive')
    >>> trie.prefix_search("ab")
    ['abracadabra', 'abbreviation', 'abbreviated', 'abbrasive']
    >>> trie.prefix_search("abr")
    ['abracadabra']
    >>> trie.prefix_search("abb")
    ['abbreviation', 'abbreviated', 'abbrasive']
    >>> trie.prefix_search("abbra")
    ['abbrasive']
    

    【讨论】:

      【解决方案2】:

      .startswith() 怎么样,在我看来这是实现搜索的简单方法。

      【讨论】:

      • 他们找到了前缀位置,他们正在尝试重建所有带有该前缀的单词。 Trie 不是单个字符串,没有什么可以使用 str.startswith()on.
      • 成本呢?提出的算法要快得多。
      猜你喜欢
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 2022-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多