Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1757a50

Browse files
add LeetCode 212. 单词搜索 II
1 parent 8eefb2f commit 1757a50

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL2Nob2NvbGF0ZTE5OTkvY2RuL2ltZy8yMDIwMDgyODE0NTUyMS5qcGc?x-oss-process=image/format,png)
2+
>仰望星空的人,不应该被嘲笑
3+
4+
## 题目描述
5+
给定一个二维网格 `board` 和一个字典中的单词列表 `words`,找出所有同时在二维网格和字典中出现的单词。
6+
7+
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中"相邻"单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
8+
9+
示例:
10+
11+
```javascript
12+
输入:
13+
words = ["oath","pea","eat","rain"] and board =
14+
[
15+
['o','a','a','n'],
16+
['e','t','a','e'],
17+
['i','h','k','r'],
18+
['i','f','l','v']
19+
]
20+
21+
输出: ["eat","oath"]
22+
说明:
23+
你可以假设所有输入都由小写字母 a-z 组成。
24+
```
25+
26+
提示:
27+
28+
```javascript
29+
你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
30+
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。
31+
```
32+
33+
来源:力扣(LeetCode)
34+
链接:https://leetcode-cn.com/problems/word-search-ii
35+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
36+
37+
38+
39+
40+
## 解题思路
41+
<a href="https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/">参考力扣官网分析:实现 Trie (前缀树)</a>
42+
43+
- 判断是否找到了,通过传递节点的END来判断
44+
45+
- 判断是否重复访问,通过动态更改走过的网格点来判断,就不需要再定义一个`vis`数组了
46+
47+
<a href="https://leetcode-cn.com/problems/word-search-ii/solution/212-dan-ci-sou-suo-ii-by-alexer-660/">参考大佬:秦时明月字典树建树解法(二)</a>
48+
49+
```javascript
50+
var findWords = function(grid, words) {
51+
// 存放最终结果集
52+
let res = []
53+
// 字典树节点
54+
class TrieNode {
55+
constructor(){
56+
this.end = false
57+
this.child = {}
58+
}
59+
}
60+
// 最终形成的字典树根节点
61+
let root = null
62+
let Trie = function(){
63+
root = new TrieNode()
64+
}
65+
// 建立字典树
66+
Trie.prototype.insert = (word) => {
67+
let cur = root
68+
for(let i=0;i<word.length;i++){
69+
if(!cur.child[word[i]]){
70+
cur.child[word[i]] = new TrieNode()
71+
}
72+
cur = cur.child[word[i]]
73+
}
74+
cur.end = true
75+
}
76+
// 创建根节点
77+
let trie = new Trie()
78+
// 进行建树操作
79+
for(let i=0;i<words.length;i++){
80+
trie.insert(words[i])
81+
}
82+
let dfs = (x,y,t,cur) => {
83+
if(cur.end){
84+
res.push(t)
85+
cur.end = false // 避免重复计算
86+
}
87+
// 剪枝条件:1.边界处理 2.下一步是否可走 3.下一步字典树是否可走
88+
if(x<0 || x>=grid.length || y<0 || y>=grid[0].length || grid[x][y] == '#' || !cur.child[grid[x][y]]) return
89+
let tmp = grid[x][y]
90+
grid[x][y] = '#' //
91+
cur = cur.child[tmp]
92+
dfs(x+1,y,t+tmp,cur) // 上下左右四个方向遍历
93+
dfs(x,y+1,t+tmp,cur)
94+
dfs(x-1,y,t+tmp,cur)
95+
dfs(x,y-1,t+tmp,cur)
96+
grid[x][y] = tmp // 回溯(还原)
97+
}
98+
// 对单词表进行全局搜索
99+
for(let i=0;i<grid.length;i++){
100+
for(let j=0;j<grid[0].length;j++){
101+
dfs(i,j,'',root)
102+
}
103+
}
104+
return res
105+
};
106+
```
107+
108+
附上完整字典树(前缀树)模板,日后可用~
109+
110+
**在 Trie 树中查找键**
111+
112+
每个键在 `trie` 中表示为从根到内部节点或叶的路径。我们用第一个键字符从根开始,。检查当前节点中与键字符对应的链接。有两种情况:
113+
114+
- 存在链接。我们移动到该链接后面路径中的下一个节点,并继续搜索下一个键字符。
115+
- 不存在链接。若已无键字符,且当前结点标记为 `isEnd`,则返回 `true`。否则有两种可能,均返回 `false `:
116+
还有键字符剩余,但无法跟随 `Trie` 树的键路径,找不到键。
117+
没有键字符剩余,但当前结点没有标记为 `isEnd`。也就是说,待查找键只是`Trie`树中另一个键的前缀。
118+
119+
![](https://img-blog.csdnimg.cn/20200913160211447.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQyOTcxOA==,size_16,color_FFFFFF,t_70#pic_center)
120+
**查找 Trie 树中的键前缀**
121+
122+
该方法与在 `Trie` 树中搜索键时使用的方法非常相似。我们从根遍历 `Trie` 树,直到键前缀中没有字符,或者无法用当前的键字符继续 `Trie` 中的路径。与上面提到的"搜索键"算法唯一的区别是,到达键前缀的末尾时,总是返回 `true`。我们不需要考虑当前 `Trie` 节点是否用 `"isend"` 标记,因为我们搜索的是键的前缀,而不是整个键。
123+
124+
![](https://img-blog.csdnimg.cn/20200913160237464.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQyOTcxOA==,size_16,color_FFFFFF,t_70#pic_center)
125+
126+
127+
作者:LeetCode
128+
链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shi-xian-trie-qian-zhui-shu-by-leetcode/
129+
来源:力扣(LeetCode)
130+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
131+
132+
133+
134+
```javascript
135+
var findWords = function(grid, words) {
136+
// 存放最终结果集
137+
let res = []
138+
// 字典树节点
139+
class TrieNode {
140+
constructor(){
141+
this.end = false
142+
this.child = {}
143+
}
144+
}
145+
// 最终形成的字典树根节点
146+
let root = null
147+
let Trie = function(){
148+
root = new TrieNode()
149+
}
150+
// 建立字典树
151+
Trie.prototype.insert = (word) => {
152+
let cur = root
153+
for(let i=0;i<word.length;i++){
154+
if(!cur.child[word[i]]){
155+
cur.child[word[i]] = new TrieNode()
156+
}
157+
cur = cur.child[word[i]]
158+
}
159+
cur.end = true
160+
}
161+
// 在 Trie 树中查找键
162+
let searchPrefix = (word) => {
163+
let cur = root
164+
for(let i=0;i<word.length;i++){
165+
if(cur.child[word[i]]){
166+
cur = cur.child[word[i]]
167+
}else{
168+
return null
169+
}
170+
}
171+
return cur
172+
}
173+
Trie.prototype.search = (word) => {
174+
let cur = searchPrefix(word)
175+
return cur !== null && cur.end
176+
}
177+
// 查找 Trie 树中的键前缀
178+
Trie.prototype.startsWith = (pre) => {
179+
return searchPrefix(pre) != null
180+
}
181+
// 创建根节点
182+
let trie = new Trie()
183+
// 进行建树操作
184+
for(let i=0;i<words.length;i++){
185+
trie.insert(words[i])
186+
}
187+
let dfs = (x,y,t,cur) => {
188+
if(cur.end){
189+
res.push(t)
190+
cur.end = false // 避免重复计算
191+
}
192+
// 剪枝条件:1.边界处理 2.下一步是否可走 3.下一步字典树是否可走
193+
if(x<0 || x>=grid.length || y<0 || y>=grid[0].length || grid[x][y] == '#' || !cur.child[grid[x][y]]) return
194+
let tmp = grid[x][y]
195+
grid[x][y] = '#' //
196+
cur = cur.child[tmp]
197+
dfs(x+1,y,t+tmp,cur) // 上下左右四个方向遍历
198+
dfs(x,y+1,t+tmp,cur)
199+
dfs(x-1,y,t+tmp,cur)
200+
dfs(x,y-1,t+tmp,cur)
201+
grid[x][y] = tmp // 回溯(还原)
202+
}
203+
// 对单词表进行全局搜索
204+
for(let i=0;i<grid.length;i++){
205+
for(let j=0;j<grid[0].length;j++){
206+
dfs(i,j,'',root)
207+
}
208+
}
209+
return res
210+
};
211+
```
212+
213+
## 最后
214+
文章产出不易,还望各位小伙伴们支持一波!
215+
216+
往期精选:
217+
218+
<a href="https://github.com/Chocolate1999/Front-end-learning-to-organize-notes">小狮子前端の笔记仓库</a>
219+
220+
<a href="https://yangchaoyi.vip/">访问超逸の博客</a>,方便小伙伴阅读玩耍~
221+
222+
![](https://img-blog.csdnimg.cn/2020090211491121.png#pic_center)
223+
224+
```javascript
225+
学如逆水行舟,不进则退
226+
```
227+
228+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /