字典树,建立init 就是把一个个单词塞进去。
功能有查找完整的,和查找前缀的,提供两个模板。
使用场景有前缀树和后缀树两种使用。

长模板:

便于理解,看了代码一看就理解的。
apple:{‘a’: {‘p’: {‘p’: {‘l’: {‘e’: {‘end’: True}}}}}} #第一次insert,最后一个’e’存在结束’end’
app: {‘a’: {‘p’: {‘p’: {‘l’: {‘e’: {‘end’: True}}, ‘end’: True}}}} #第二次insert,第二个’p’存在结束’end’

  1. class Trie:
  2. def __init__(self):
  3. self.tree={}
  4. def insert(self, word: str) -> None:
  5. t=self.tree
  6. for char in word:
  7. if char not in t:
  8. t[char]={}
  9. t=t[char]
  10. t["end"]=True
  11. def search(self, word: str) -> bool:
  12. t=self.tree
  13. for char in word:
  14. if char not in t:
  15. return False
  16. t=t[char]
  17. return "end" in t
  18. def startsWith(self, prefix: str) -> bool:
  19. t=self.tree
  20. for char in prefix:
  21. if char not in t:
  22. return False
  23. t=t[char]
  24. return True

短模板

便于抄写,都是高端python写法,reduce 和defaultdict,不展开了。

  1. from collections import defaultdict
  2. from functools import reduce
  3. TrieNode = lambda: defaultdict(TrieNode)
  4. class Trie:
  5. def __init__(self):
  6. self.trie = TrieNode()
  7. def insert(self, word):
  8. reduce(dict.__getitem__, word, self.trie)['end'] = True
  9. def search(self, word):
  10. return reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).get('end', False)
  11. def startsWith(self, word):
  12. return bool(reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).keys())

例题:

一般Trie 都是要继续迭代node的。
所以Trie类光会抄模板也不一定有用,要理解现在的node是什么,该怎么用,要不要从头开始遍历tree

212. 单词搜索 II

  1. from collections import defaultdict
  2. from functools import reduce
  3. TrieNode = lambda: defaultdict(TrieNode)
  4. class Trie:
  5. def __init__(self):
  6. self.trie = TrieNode()
  7. def insert(self, word):
  8. reduce(dict.__getitem__, word, self.trie)['end'] = True
  9. def search(self, word):
  10. return reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).get('end', False)
  11. def startsWith(self, word):
  12. return bool(reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).keys())
  13. class Solution:
  14. def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
  15. if not board or not board[0]:return []
  16. m,n=len(board),len(board[0])
  17. self.tree=Trie()
  18. self.ans=[]
  19. for word in words:
  20. self.tree.insert(word)
  21. directions =[(1,0),(-1,0),(0,1),(0,-1)]
  22. def dfs(i,j,t,s):
  23. if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or board[i][j] not in t: return
  24. char=board[i][j]
  25. path = s+char
  26. board[i][j]="#"
  27. if "end" in t[char]:
  28. self.ans.append(path)
  29. for ix,iy in directions:
  30. x,y=i+ix,j+iy
  31. dfs(x,y,t[char],path)
  32. board[i][j]=char
  33. for i in range(m):
  34. for j in range(n):
  35. t=self.tree
  36. dfs(i,j,t.trie,"")
  37. return list(set(self.ans))

820. 单词的压缩编码

解法1:建树扫一遍,再扫一遍,扫到end的时候len(t)==1,说明不能压缩,如果len(t)>1,说明可以压缩。
解法2:先按长度排序,一边扫一边insert,如果startwith,不更新ans不insert,否则insert和更新ans。

  1. from collections import defaultdict
  2. from functools import reduce
  3. TrieNode = lambda: defaultdict(TrieNode)
  4. class Trie:
  5. def __init__(self):
  6. self.trie = TrieNode()
  7. def insert(self, word):
  8. reduce(dict.__getitem__, word, self.trie)['end'] = True
  9. def search(self, word):
  10. return reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).get('end', False)
  11. def startsWith(self, word):
  12. return bool(reduce(lambda d,k: d[k] if k in d else TrieNode(), word, self.trie).keys())
  13. class Solution:
  14. def minimumLengthEncoding(self, words: List[str]) -> int:
  15. tree=Trie()
  16. words =set(words)
  17. for word in words:
  18. tree.insert(word[::-1])
  19. ans=0
  20. for word in words:
  21. t=tree.trie
  22. for c in word[::-1]:
  23. t=t[c]
  24. if len(t)==1:
  25. ans+=len(word)+1
  26. else:
  27. continue
  28. return ans