forked from HuberTRoy/leetCode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Trie.py
149 lines (120 loc) · 3.91 KB
/
Trie.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
前缀树又叫字典树,该树会覆盖多个相同的字符以形成空间上的优势。
如:
rat 与 rain
r
a
t i
n
最终会形成这样的树。
字典树有多种实现方式,下面直接用了列表(数组)来实现。
测试用例:
https://leetcode.com/problems/implement-trie-prefix-tree/description/
使用Python 中的字典可以直接形成这种树,所以弃用这种方式,用类的思路实现了一下。
"""
class TrieNode(object):
# __slots__ 考虑到TrieNode会大量创建,使用 __slot__来减少内存的占用。
# 在测试的15个例子中:
# 使用 __slots__会加快创建,平均的耗时为290ms-320ms。
# 而不使用则在 340ms-360ms之间。
# 创建的越多效果越明显。
# 当然,使用字典而不是类的方式会更加更加更加高效。
__slots__ = {'value', 'nextNodes', 'breakable'}
def __init__(self, value, nextNode=None):
self.value = value
if nextNode:
self.nextNodes = [nextNode]
else:
self.nextNodes = []
self.breakable = False
def addNext(self, nextNode):
self.nextNodes.append(nextNode)
def setBreakable(self, enable):
self.breakable = enable
def __eq__(self, other):
return self.value == other
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = []
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
self.makeATrieNodes(word)
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
for i in self.root:
if i == word[0]:
return self._search(i, word[1:])
return False
def _search(self, root, word):
if not word:
if root.breakable:
return True
return False
if not root.nextNodes:
return False
for i in root.nextNodes:
if i == word[0]:
return self._search(i, 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
:rtype: bool
"""
for i in self.root:
if i == prefix[0]:
return self._startWith(i, prefix[1:])
return False
def _startWith(self, root, prefix):
if not prefix:
return True
if not root.nextNodes:
return False
for i in root.nextNodes:
if i == prefix[0]:
return self._startWith(i, prefix[1:])
return False
def makeATrieNodes(self, word):
for j in self.root:
if word[0] == j:
rootWord = j
break
else:
rootWord = TrieNode(word[0])
self.root.append(rootWord)
for i in word[1:]:
nextNode = TrieNode(i)
rootWord.addNext(nextNode)
rootWord = nextNode
rootWord.setBreakable(True)
return
# has the letter.
word = word[1:]
while 1:
if not word:
rootWord.setBreakable(True)
break
for i in rootWord.nextNodes:
if i == word[0]:
rootWord = i
word = word[1:]
break
else:
for i in word:
nextNode = TrieNode(i)
rootWord.addNext(nextNode)
rootWord = nextNode
rootWord.setBreakable(True)
break