47
47
48
48
** 方法一:前缀树 + DFS**
49
49
50
+ 我们首先将 ` words ` 中的单词构建成前缀树,前缀树的每个节点包含一个长度为 $26$ 的数组 ` children ` ,表示该节点的子节点,数组的下标表示子节点对应的字符,数组的值表示子节点的引用。同时,每个节点还包含一个整数 ` ref ` ,表示该节点对应的单词在 ` words ` 中的引用,如果该节点不是单词的结尾,则 ` ref ` 的值为 $-1$。
51
+
52
+ 接下来,我们对于 ` board ` 中的每个单元格,从该单元格出发,进行深度优先搜索,搜索过程中,如果当前单词不是前缀树中的单词,则剪枝,如果当前单词是前缀树中的单词,则将该单词加入答案,并将该单词在前缀树中的引用置为 $-1$,表示该单词已经被找到,不需要再次搜索。
53
+
54
+ 最后,我们将答案返回即可。
55
+
56
+ 时间复杂度 $(m \times n \times 3^{l-1})$,空间复杂度 $(k \times l)$。其中 $m$ 和 $n$ 分别是 ` board ` 的行数和列数。而 $l$ 和 $k$ 分别是 ` words ` 中的单词的平均长度和单词的个数。
57
+
50
58
<!-- tabs:start -->
51
59
52
60
### ** Python3**
56
64
``` python
57
65
class Trie :
58
66
def __init__ (self ):
59
- self .children = [None ] * 26
60
- self .w = ' '
67
+ self .children: List[Trie | None ] = [None ] * 26
68
+ self .ref: int = - 1
61
69
62
- def insert (self , w ):
70
+ def insert (self , w : str , ref : int ):
63
71
node = self
64
72
for c in w:
65
73
idx = ord (c) - ord (' a' )
66
74
if node.children[idx] is None :
67
75
node.children[idx] = Trie()
68
76
node = node.children[idx]
69
- node.w = w
77
+ node.ref = ref
70
78
71
79
72
80
class Solution :
73
81
def findWords (self , board : List[List[str ]], words : List[str ]) -> List[str ]:
74
- def dfs (node , i , j ):
82
+ def dfs (node : Trie , i : int , j : int ):
75
83
idx = ord (board[i][j]) - ord (' a' )
76
84
if node.children[idx] is None :
77
85
return
78
86
node = node.children[idx]
79
- if node.w:
80
- ans.add(node.w)
87
+ if node.ref >= 0 :
88
+ ans.append(words[node.ref])
89
+ node.ref = - 1
81
90
c = board[i][j]
82
- board[i][j] = ' 0 '
83
- for a, b in [[ 0 , - 1 ], [ 0 , 1 ], [ 1 , 0 ], [ - 1 , 0 ]] :
91
+ board[i][j] = ' # '
92
+ for a, b in pairwise(( - 1 , 0 , 1 , 0 , - 1 )) :
84
93
x, y = i + a, j + b
85
- if 0 <= x < m and 0 <= y < n and board[x][y] != ' 0 ' :
94
+ if 0 <= x < m and 0 <= y < n and board[x][y] != ' # ' :
86
95
dfs(node, x, y)
87
- board[i][y ] = c
96
+ board[i][j ] = c
88
97
89
- trie = Trie()
90
- for w in words:
91
- trie.insert(w)
92
- ans = set ()
98
+ tree = Trie()
99
+ for i, w in enumerate (words):
100
+ tree.insert(w, i)
93
101
m, n = len (board), len (board[0 ])
102
+ ans = []
94
103
for i in range (m):
95
104
for j in range (n):
96
- dfs(trie , i, j)
97
- return list ( ans)
105
+ dfs(tree , i, j)
106
+ return ans
98
107
```
99
108
100
109
### ** Java**
@@ -104,41 +113,40 @@ class Solution:
104
113
``` java
105
114
class Trie {
106
115
Trie [] children = new Trie [26 ];
107
- String w ;
116
+ int ref = - 1 ;
108
117
109
- void insert (String w ) {
118
+ public void insert (String w , int ref ) {
110
119
Trie node = this ;
111
- for (char c : w . toCharArray() ) {
112
- c -= ' a' ;
113
- if (node. children[c ] == null ) {
114
- node. children[c ] = new Trie ();
120
+ for (int i = 0 ; i < w . length(); ++ i ) {
121
+ int j = w . charAt(i) - ' a' ;
122
+ if (node. children[j ] == null ) {
123
+ node. children[j ] = new Trie ();
115
124
}
116
- node = node. children[c ];
125
+ node = node. children[j ];
117
126
}
118
- node. w = w ;
127
+ node. ref = ref ;
119
128
}
120
129
}
121
130
122
131
class Solution {
123
- private Set<String > ans = new HashSet<> ();
124
- private int m;
125
- private int n;
126
132
private char [][] board;
133
+ private String [] words;
134
+ private List<String > ans = new ArrayList<> ();
127
135
128
136
public List<String > findWords (char [][] board , String [] words ) {
129
- Trie trie = new Trie ();
130
- for (String w : words) {
131
- trie. insert(w);
132
- }
133
- m = board. length;
134
- n = board[0 ]. length;
135
137
this . board = board;
138
+ this . words = words;
139
+ Trie tree = new Trie ();
140
+ for (int i = 0 ; i < words. length; ++ i) {
141
+ tree. insert(words[i], i);
142
+ }
143
+ int m = board. length, n = board[0 ]. length;
136
144
for (int i = 0 ; i < m; ++ i) {
137
145
for (int j = 0 ; j < n; ++ j) {
138
- dfs(trie , i, j);
146
+ dfs(tree , i, j);
139
147
}
140
148
}
141
- return new ArrayList<> ( ans) ;
149
+ return ans;
142
150
}
143
151
144
152
private void dfs (Trie node , int i , int j ) {
@@ -147,15 +155,16 @@ class Solution {
147
155
return ;
148
156
}
149
157
node = node. children[idx];
150
- if (node. w != null ) {
151
- ans. add(node. w);
158
+ if (node. ref != - 1 ) {
159
+ ans. add(words[node. ref]);
160
+ node. ref = - 1 ;
152
161
}
153
162
char c = board[i][j];
154
- board[i][j] = ' 0 ' ;
163
+ board[i][j] = ' # ' ;
155
164
int [] dirs = {- 1 , 0 , 1 , 0 , - 1 };
156
165
for (int k = 0 ; k < 4 ; ++ k) {
157
166
int x = i + dirs[k], y = j + dirs[k + 1 ];
158
- if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] != ' 0 ' ) {
167
+ if (x >= 0 && x < board . length && y >= 0 && y < board[ 0 ] . length && board[x][y] != ' # ' ) {
159
168
dfs(node, x, y);
160
169
}
161
170
}
@@ -170,51 +179,63 @@ class Solution {
170
179
class Trie {
171
180
public:
172
181
vector<Trie* > children;
173
- string w;
182
+ int ref;
183
+
174
184
Trie()
175
- : children(26)
176
- , w("" ) { }
185
+ : children(26, nullptr )
186
+ , ref(-1 ) {}
177
187
178
- void insert(string& w) {
188
+ void insert (const string& w, int ref ) {
179
189
Trie* node = this;
180
190
for (char c : w) {
181
191
c -= 'a';
182
- if (!node->children[c]) node->children[c] = new Trie();
192
+ if (!node->children[ c] ) {
193
+ node->children[ c] = new Trie();
194
+ }
183
195
node = node->children[ c] ;
184
196
}
185
- node->w = w ;
197
+ node->ref = ref ;
186
198
}
187
199
};
188
200
189
201
class Solution {
190
202
public:
191
- vector<int > dirs = {-1, 0, 1, 0, -1};
192
-
193
203
vector<string > findWords(vector<vector<char >>& board, vector<string >& words) {
194
- Trie* trie = new Trie();
195
- unordered_set<string> res;
196
- for (auto& w : words) trie->insert(w);
197
- for (int i = 0; i < board.size(); ++i)
198
- for (int j = 0; j < board[0].size(); ++j)
199
- dfs(trie, i, j, board, res);
204
+ Trie* tree = new Trie();
205
+ for (int i = 0; i < words.size(); ++i) {
206
+ tree->insert(words[ i] , i);
207
+ }
200
208
vector<string > ans;
201
- for (auto& w : res) ans.emplace_back(w);
202
- return ans;
203
- }
209
+ int m = board.size(), n = board[ 0] .size();
204
210
205
- void dfs (Trie* node, int i, int j, vector<vector<char >>& board, unordered_set<string >& res) {
206
- int idx = board[ i] [ j ] - 'a';
207
- if (!node->children[ idx] ) return;
208
- node = node->children[ idx] ;
209
- if (node->w != "") res.insert(node->w);
210
- char c = board[ i] [ j ] ;
211
- board[ i] [ j ] = '0';
211
+ function<void(Trie*, int, int)> dfs = [&](Trie* node, int i, int j) {
212
+ int idx = board[i][j] - 'a';
213
+ if (!node->children[idx]) {
214
+ return;
215
+ }
216
+ node = node->children[idx];
217
+ if (node->ref != -1) {
218
+ ans.emplace_back(words[node->ref]);
219
+ node->ref = -1;
220
+ }
221
+ int dirs[5] = {-1, 0, 1, 0, -1};
222
+ char c = board[i][j];
223
+ board[i][j] = '#';
224
+ for (int k = 0; k < 4; ++k) {
225
+ int x = i + dirs[k], y = j + dirs[k + 1];
226
+ if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] != '#') {
227
+ dfs(node, x, y);
228
+ }
229
+ }
230
+ board[i][j] = c;
231
+ };
212
232
213
- for (int k = 0; k < 4; ++k) {
214
- int x = i + dirs[k], y = j + dirs[k + 1];
215
- if (x >= 0 && x < board.size() && y >= 0 && y < board[0].size() && board[x][y] != '0') dfs(node, x, y, board, res);
233
+ for (int i = 0; i < m; ++i) {
234
+ for (int j = 0; j < n; ++j) {
235
+ dfs(tree, i, j);
236
+ }
216
237
}
217
- board[i][j] = c ;
238
+ return ans ;
218
239
}
219
240
};
220
241
```
@@ -224,62 +245,122 @@ public:
224
245
```go
225
246
type Trie struct {
226
247
children [26]*Trie
227
- w string
248
+ ref int
228
249
}
229
250
230
251
func newTrie() *Trie {
231
- return &Trie{}
252
+ return &Trie{ref: -1 }
232
253
}
233
- func (this *Trie) insert(word string) {
254
+ func (this *Trie) insert(w string, ref int ) {
234
255
node := this
235
- for _, c := range word {
256
+ for _, c := range w {
236
257
c -= 'a'
237
258
if node.children[c] == nil {
238
259
node.children[c] = newTrie()
239
260
}
240
261
node = node.children[c]
241
262
}
242
- node.w = word
263
+ node.ref = ref
243
264
}
244
265
245
- func findWords(board [][]byte, words []string) []string {
266
+ func findWords(board [][]byte, words []string) (ans []string) {
246
267
trie := newTrie()
247
- for _ , w := range words {
248
- trie.insert(w)
268
+ for i , w := range words {
269
+ trie.insert(w, i )
249
270
}
250
271
m, n := len(board), len(board[0])
251
- res := map[string]bool{}
252
- var dfs func(node *Trie, i, j int)
272
+ var dfs func(*Trie, int, int)
253
273
dfs = func(node *Trie, i, j int) {
254
274
idx := board[i][j] - 'a'
255
275
if node.children[idx] == nil {
256
276
return
257
277
}
258
278
node = node.children[idx]
259
- if node.w != "" {
260
- res[node.w] = true
279
+ if node.ref != -1 {
280
+ ans = append(ans, words[node.ref])
281
+ node.ref = -1
261
282
}
262
- dirs := []int{-1, 0, 1, 0, -1}
263
283
c := board[i][j]
264
- board[i][j] = '0'
284
+ board[i][j] = '#'
285
+ dirs := [5]int{-1, 0, 1, 0, -1}
265
286
for k := 0; k < 4; k++ {
266
287
x, y := i+dirs[k], j+dirs[k+1]
267
- if x >= 0 && x < m && y >= 0 && y < n && board[x][y] != '0 ' {
288
+ if x >= 0 && x < m && y >= 0 && y < n && board[x][y] != '# ' {
268
289
dfs(node, x, y)
269
290
}
270
291
}
271
292
board[i][j] = c
272
293
}
273
- for i, row := range board {
274
- for j := range row {
294
+ for i := 0; i < m; i++ {
295
+ for j := 0; j < n; j++ {
275
296
dfs(trie, i, j)
276
297
}
277
298
}
278
- var ans []string
279
- for v := range res {
280
- ans = append(ans, v)
281
- }
282
- return ans
299
+ return
300
+ }
301
+ ```
302
+
303
+ ### ** TypeScript**
304
+
305
+ ``` ts
306
+ class Trie {
307
+ children: Trie [];
308
+ ref: number ;
309
+
310
+ constructor () {
311
+ this .children = new Array (26 );
312
+ this .ref = - 1 ;
313
+ }
314
+
315
+ insert(w : string , ref : number ): void {
316
+ let node: Trie = this ;
317
+ for (let i = 0 ; i < w .length ; i ++ ) {
318
+ const c = w .charCodeAt (i ) - 97 ;
319
+ if (node .children [c ] == null ) {
320
+ node .children [c ] = new Trie ();
321
+ }
322
+ node = node .children [c ];
323
+ }
324
+ node .ref = ref ;
325
+ }
326
+ }
327
+
328
+ function findWords(board : string [][], words : string []): string [] {
329
+ const tree = new Trie ();
330
+ for (let i = 0 ; i < words .length ; ++ i ) {
331
+ tree .insert (words [i ], i );
332
+ }
333
+ const m = board .length ;
334
+ const n = board [0 ].length ;
335
+ const ans: string [] = [];
336
+ const dirs: number [] = [- 1 , 0 , 1 , 0 , - 1 ];
337
+ const dfs = (node : Trie , i : number , j : number ) => {
338
+ const idx = board [i ][j ].charCodeAt (0 ) - 97 ;
339
+ if (node .children [idx ] == null ) {
340
+ return ;
341
+ }
342
+ node = node .children [idx ];
343
+ if (node .ref != - 1 ) {
344
+ ans .push (words [node .ref ]);
345
+ node .ref = - 1 ;
346
+ }
347
+ const c = board [i ][j ];
348
+ board [i ][j ] = ' #' ;
349
+ for (let k = 0 ; k < 4 ; ++ k ) {
350
+ const x = i + dirs [k ];
351
+ const y = j + dirs [k + 1 ];
352
+ if (x >= 0 && x < m && y >= 0 && y < n && board [x ][y ] != ' #' ) {
353
+ dfs (node , x , y );
354
+ }
355
+ }
356
+ board [i ][j ] = c ;
357
+ };
358
+ for (let i = 0 ; i < m ; ++ i ) {
359
+ for (let j = 0 ; j < n ; ++ j ) {
360
+ dfs (tree , i , j );
361
+ }
362
+ }
363
+ return ans ;
283
364
}
284
365
```
285
366
0 commit comments