Skip to content

Commit b724e44

Browse files
author
robot
committed
feat: $212
1 parent bfdcfc3 commit b724e44

File tree

4 files changed

+60
-58
lines changed

4 files changed

+60
-58
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
466466
- [0145. 二叉树的后序遍历](./problems/145.binary-tree-postorder-traversal.md)
467467
- [0146. LRU 缓存机制](./problems/146.lru-cache.md)
468468
- [0154. 寻找旋转排序数组中的最小值 II](./problems/154.find-minimum-in-rotated-sorted-array-ii.md)
469-
<!-- - [0212. 单词搜索 II](./problems/212.word-search-ii.md) -->
469+
- [0212. 单词搜索 II](./problems/212.word-search-ii.md)
470470
- [0239. 滑动窗口最大值](./problems/239.sliding-window-maximum.md) 👍
471471
- [0295. 数据流的中位数](./problems/295.find-median-from-data-stream.md)
472472
- [0297. 二叉树的序列化与反序列化](./problems/297.serialize-and-deserialize-binary-tree.md) 91

SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@
288288
- [0145. 二叉树的后序遍历](./problems/145.binary-tree-postorder-traversal.md)
289289
- [0146. LRU 缓存机制](./problems/146.lru-cache.md)
290290
- [0154. 寻找旋转排序数组中的最小值 II](./problems/154.find-minimum-in-rotated-sorted-array-ii.md)
291-
<!-- - [0212. 单词搜索 II](./problems/212.word-search-ii.md) -->
291+
- [0212. 单词搜索 II](./problems/212.word-search-ii.md)
292292
- [0239. 滑动窗口最大值](./problems/239.sliding-window-maximum.md)
293293
- [0295. 数据流的中位数](./problems/295.find-median-from-data-stream.md)
294294
- [0297. 二叉树的序列化与反序列化](./problems/297.serialize-and-deserialize-binary-tree.md) 91

problems/212.word-search-ii.md

Lines changed: 28 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ words = ["oath","pea","eat","rain"] and board =
6262

6363
刚才我提到了一个关键词“前缀”,我们考虑使用前缀树来优化。使得复杂度降低为$O(h)$, 其中 h 是前缀树深度,也就是最长的字符串长度。
6464

65+
关于前缀树,可以参考我的[前缀树](../thinkings/trie.md) 专题。
66+
6567
![](https://tva1.sinaimg.cn/large/007S8ZIlly1ghlua4m3ofj30mz0gqdhc.jpg)
6668

69+
值得注意的是如果每次 dfs 都使用 startsWith 来判断,那么会超时。我们可以将当前遍历到的 trie 节点 以参数传递到 dfs 中,这样可以进一步减少复杂度。
70+
6771
## 关键点
6872

6973
- 前缀树(也叫字典树),英文名 Trie(读作 tree 或者 try)
@@ -79,77 +83,46 @@ Python3 Code:
7983
关于 Trie 的代码:
8084

8185
```python
86+
from collections import defaultdict
8287
class Trie:
83-
8488
def __init__(self):
85-
"""
86-
Initialize your data structure here.
87-
"""
88-
self.Trie = {}
89+
self.children = defaultdict(Trie)
90+
self.word = ""
8991

9092
def insert(self, word):
91-
"""
92-
Inserts a word into the trie.
93-
:type word: str
94-
:rtype: void
95-
"""
96-
curr = self.Trie
97-
for w in word:
98-
if w not in curr:
99-
curr[w] = {}
100-
curr = curr[w]
101-
curr['#'] = 1
102-
103-
def startsWith(self, prefix):
104-
"""
105-
Returns if there is any word in the trie that starts with the given prefix.
106-
:type prefix: str
107-
:rtype: bool
108-
"""
109-
110-
curr = self.Trie
111-
for w in prefix:
112-
if w not in curr:
113-
return False
114-
curr = curr[w]
115-
return True
93+
cur = self
94+
for c in word:
95+
cur = cur.children[c]
96+
cur.word = word
11697
```
11798

11899
主逻辑代码:
119100

120101
```python
102+
121103
class Solution:
122104
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
123-
m = len(board)
124-
if m == 0:
125-
return []
126-
n = len(board[0])
105+
def dfs(row, col, cur):
106+
if row < 0 or row >= m or col < 0 or col >= n or board[row][col] == '.' or board[row][col] not in cur.children: return
107+
c = board[row][col]
108+
cur = cur.children[c]
109+
if cur.word != '': ans.add(cur.word)
110+
board[row][col] = '.'
111+
dfs(row+1,col, cur)
112+
dfs(row-1,col, cur)
113+
dfs(row,col+1, cur)
114+
dfs(row,col-1, cur)
115+
board[row][col] = c
116+
m, n = len(board), len(board[0])
117+
ans = set()
127118
trie = Trie()
128-
seen = None
129-
res = set()
119+
words = set(words)
130120
for word in words:
131121
trie.insert(word)
132-
133-
def dfs(s, i, j):
134-
if (i, j) in seen or i < 0 or i >= m or j < 0 or j >= n or not trie.startsWith(s):
135-
return
136-
s += board[i][j]
137-
seen[(i, j)] = True
138-
139-
if s in words:
140-
res.add(s)
141-
dfs(s, i + 1, j)
142-
dfs(s, i - 1, j)
143-
dfs(s, i, j + 1)
144-
dfs(s, i, j - 1)
145-
146-
del seen[(i, j)]
147-
148122
for i in range(m):
149123
for j in range(n):
150-
seen = dict()
151-
dfs("", i, j)
152-
return list(res)
124+
dfs(i, j, trie)
125+
return list(ans)
153126
```
154127

155128
## 相关题目

thinkings/trie.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Trie(来自公众号力扣加加的活动《91天学算法》的讲义)
1+
# Trie(来自公众号力扣加加的活动《91 天学算法》的讲义)
22

33
## 简介
44

@@ -225,3 +225,32 @@ class Trie:
225225
最后给大家提供了两种语言的前缀树模板,大家如果需要用,直接将其封装成标准 API 调用即可。
226226

227227
基于前缀树的题目变化通常不大, 使用模板就可以解决。如何知道该使用前缀树优化是一个难点,不过大家只要牢牢记一点即可,那就是**算法的复杂度瓶颈在字符串查找,并且字符串有很多公共前缀,就可以用前缀树优化**
228+
229+
## 扩展
230+
231+
还有一种建树方法,我们简单介绍一下。
232+
233+
我们可以用递归的方式来建树,每一个节点称为 TrieNode。
234+
235+
TrieNode 接口如下:
236+
237+
```py
238+
children: TrieNode[] # 子节点
239+
word: string # 当前节点结尾的单词
240+
```
241+
242+
```py
243+
from collections import defaultdict
244+
class Trie:
245+
def __init__(self):
246+
self.children = defaultdict(Trie)
247+
self.word = ""
248+
249+
def insert(self, word):
250+
cur = self
251+
for c in word:
252+
cur = cur.children[c]
253+
cur.word = word
254+
```
255+
256+
这种方法在某些题目中比较有用,比如 [212. 单词搜索 II](https://github.com/azl397985856/leetcode/blob/master/problems/212.word-search-ii.md)

0 commit comments

Comments
 (0)