Skip to content

Commit f09d488

Browse files
committed
feat: add solutions to lc problem: No.0212
No.0212.Word Search II
1 parent 782e347 commit f09d488

File tree

7 files changed

+492
-270
lines changed

7 files changed

+492
-270
lines changed

solution/0200-0299/0212.Word Search II/README.md

Lines changed: 171 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@
4747

4848
**方法一:前缀树 + DFS**
4949

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+
5058
<!-- tabs:start -->
5159

5260
### **Python3**
@@ -56,45 +64,46 @@
5664
```python
5765
class Trie:
5866
def __init__(self):
59-
self.children = [None] * 26
60-
self.w = ''
67+
self.children: List[Trie | None] = [None] * 26
68+
self.ref: int = -1
6169

62-
def insert(self, w):
70+
def insert(self, w: str, ref: int):
6371
node = self
6472
for c in w:
6573
idx = ord(c) - ord('a')
6674
if node.children[idx] is None:
6775
node.children[idx] = Trie()
6876
node = node.children[idx]
69-
node.w = w
77+
node.ref = ref
7078

7179

7280
class Solution:
7381
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):
7583
idx = ord(board[i][j]) - ord('a')
7684
if node.children[idx] is None:
7785
return
7886
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
8190
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)):
8493
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] != '#':
8695
dfs(node, x, y)
87-
board[i][y] = c
96+
board[i][j] = c
8897

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)
93101
m, n = len(board), len(board[0])
102+
ans = []
94103
for i in range(m):
95104
for j in range(n):
96-
dfs(trie, i, j)
97-
return list(ans)
105+
dfs(tree, i, j)
106+
return ans
98107
```
99108

100109
### **Java**
@@ -104,41 +113,40 @@ class Solution:
104113
```java
105114
class Trie {
106115
Trie[] children = new Trie[26];
107-
String w;
116+
int ref = -1;
108117

109-
void insert(String w) {
118+
public void insert(String w, int ref) {
110119
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();
115124
}
116-
node = node.children[c];
125+
node = node.children[j];
117126
}
118-
node.w = w;
127+
node.ref = ref;
119128
}
120129
}
121130

122131
class Solution {
123-
private Set<String> ans = new HashSet<>();
124-
private int m;
125-
private int n;
126132
private char[][] board;
133+
private String[] words;
134+
private List<String> ans = new ArrayList<>();
127135

128136
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;
135137
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;
136144
for (int i = 0; i < m; ++i) {
137145
for (int j = 0; j < n; ++j) {
138-
dfs(trie, i, j);
146+
dfs(tree, i, j);
139147
}
140148
}
141-
return new ArrayList<>(ans);
149+
return ans;
142150
}
143151

144152
private void dfs(Trie node, int i, int j) {
@@ -147,15 +155,16 @@ class Solution {
147155
return;
148156
}
149157
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;
152161
}
153162
char c = board[i][j];
154-
board[i][j] = '0';
163+
board[i][j] = '#';
155164
int[] dirs = {-1, 0, 1, 0, -1};
156165
for (int k = 0; k < 4; ++k) {
157166
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] != '#') {
159168
dfs(node, x, y);
160169
}
161170
}
@@ -170,51 +179,63 @@ class Solution {
170179
class Trie {
171180
public:
172181
vector<Trie*> children;
173-
string w;
182+
int ref;
183+
174184
Trie()
175-
: children(26)
176-
, w("") { }
185+
: children(26, nullptr)
186+
, ref(-1) {}
177187

178-
void insert(string& w) {
188+
void insert(const string& w, int ref) {
179189
Trie* node = this;
180190
for (char c : w) {
181191
c -= 'a';
182-
if (!node->children[c]) node->children[c] = new Trie();
192+
if (!node->children[c]) {
193+
node->children[c] = new Trie();
194+
}
183195
node = node->children[c];
184196
}
185-
node->w = w;
197+
node->ref = ref;
186198
}
187199
};
188200

189201
class Solution {
190202
public:
191-
vector<int> dirs = {-1, 0, 1, 0, -1};
192-
193203
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+
}
200208
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();
204210

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+
};
212232

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+
}
216237
}
217-
board[i][j] = c;
238+
return ans;
218239
}
219240
};
220241
```
@@ -224,62 +245,122 @@ public:
224245
```go
225246
type Trie struct {
226247
children [26]*Trie
227-
w string
248+
ref int
228249
}
229250
230251
func newTrie() *Trie {
231-
return &Trie{}
252+
return &Trie{ref: -1}
232253
}
233-
func (this *Trie) insert(word string) {
254+
func (this *Trie) insert(w string, ref int) {
234255
node := this
235-
for _, c := range word {
256+
for _, c := range w {
236257
c -= 'a'
237258
if node.children[c] == nil {
238259
node.children[c] = newTrie()
239260
}
240261
node = node.children[c]
241262
}
242-
node.w = word
263+
node.ref = ref
243264
}
244265
245-
func findWords(board [][]byte, words []string) []string {
266+
func findWords(board [][]byte, words []string) (ans []string) {
246267
trie := newTrie()
247-
for _, w := range words {
248-
trie.insert(w)
268+
for i, w := range words {
269+
trie.insert(w, i)
249270
}
250271
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)
253273
dfs = func(node *Trie, i, j int) {
254274
idx := board[i][j] - 'a'
255275
if node.children[idx] == nil {
256276
return
257277
}
258278
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
261282
}
262-
dirs := []int{-1, 0, 1, 0, -1}
263283
c := board[i][j]
264-
board[i][j] = '0'
284+
board[i][j] = '#'
285+
dirs := [5]int{-1, 0, 1, 0, -1}
265286
for k := 0; k < 4; k++ {
266287
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] != '#' {
268289
dfs(node, x, y)
269290
}
270291
}
271292
board[i][j] = c
272293
}
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++ {
275296
dfs(trie, i, j)
276297
}
277298
}
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;
283364
}
284365
```
285366

0 commit comments

Comments
 (0)