LeetCode 676. Implement Magic Dictionary - 前缀树(Trie Tree or Prefix Tree)系列题8

Design a data structure that is initialized with a list of different words. Provided a string, you should determine if you can change exactly one character in this string to match any word in the data structure.

Implement the MagicDictionary class:

  • MagicDictionary() Initializes the object.
  • void buildDict(String[] dictionary) Sets the data structure with an array of distinct strings dictionary.
  • bool search(String searchWord) Returns true if you can change exactly one character in searchWord to match any string in the data structure, otherwise returns false.

Example 1:

Input
["MagicDictionary", "buildDict", "search", "search", "search", "search"]
[[], [["hello", "leetcode"]], ["hello"], ["hhllo"], ["hell"], ["leetcoded"]]
Output
[null, null, false, true, false, false]

Explanation
MagicDictionary magicDictionary = new MagicDictionary();
magicDictionary.buildDict(["hello", "leetcode"]);
magicDictionary.search("hello"); // return False
magicDictionary.search("hhllo"); // We can change the second 'h' to 'e' to match "hello" so we return True
magicDictionary.search("hell"); // return False
magicDictionary.search("leetcoded"); // return False

Constraints:

  • 1 <= dictionary.length <= 100
  • 1 <= dictionary[i].length <= 100
  • dictionary[i] consists of only lower-case English letters.
  • All the strings in dictionary are distinct.
  • 1 <= searchWord.length <= 100
  • searchWord consists of only lower-case English letters.
  • buildDict will be called only once before search.
  • At most 100 calls will be made to search.

又是一道典型的关于前缀树的题,还是LeetCode 208. Implement Trie (Prefix Tree) 的拓展。不同的地方是查找的条件不同,给定一个单词必须也只能修改其中一个字母为任意字母,问是否能在字典集里找到修改后的单词?

前缀树(Trie)数据结构定义和单词插入函数跟LeetCode 208. Implement Trie (Prefix Tree) 是一样的。

查找函数:根据单词的每一个字母沿着前缀树的根节点往下搜索。在处理每一个字母时,会有如下两种情况:

1)在这个字母之前没有改变过字母:需要判断当前节点的所有非空子节点,对于与当前字母匹配的节点表示仍然不用改变字母可以继续往后匹配搜索(之后还有一次改变机会);对于其它节点表示在这个节点改变了一次字母然后继续往后匹配搜索(之后没有改变机会,必须严格匹配直到最后)。

2)在这个字母之前已经改变过一次字母,那就查找严格匹配的子节点,如为空节点可以直接停止;如不为空则可以继续往后搜索。

按以上两种情况处理每个字母直到最后一个字母,最后一个节点需要判断是否为有效单词还需要判断之前是否有使用一次改变的机会。只有两个条件都满足才表示找到可以匹配的单词。

class TrieNode:
    def __init__(self):
        self.end = False
        self.children = [None] * 26
        
class MagicDictionary:

    def __init__(self):
        self.root = TrieNode()

    def buildDict(self, dictionary: List[str]) -> None:
        for word in dictionary:
            node = self.root
            for c in word:
                idx = ord(c) - ord('a')
                if not node.children[idx]:
                    node.children[idx] = TrieNode()
                node = node.children[idx]
            node.end = True

    def search(self, searchWord: str) -> bool:
        def helper(word, node, flag): #flag表示是否改变一次字母
            if not word:
                return node.end and flag
            
            for j in range(26):
                child = node.children[j]
                if not child:
                    continue
                
                c = chr(ord('a') + j)
                if c == word[0]:
                    if helper(word[1:], child, flag):
                        return True
                else:
                    if flag == False:
                        if helper(word[1:], child, True):
                            return True
            return False
        
        return helper(searchWord, self.root, False)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值