212. Word Search II

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
class Solution {
private static class Trie {
private final Trie[] children;
private boolean isEnd;

public Trie() {
this.children = new Trie[26];
this.isEnd = false;
}

public void add(String word) {
Trie trie = this;
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
int offset = c - 'a';
if (trie.children[offset] == null) {
trie.children[offset] = new Trie();
}
trie = trie.children[offset];
}
trie.isEnd = true;
}
}

private static final int[][] DIRECTIONS = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

public List<String> findWords(char[][] board, String[] words) {
int m = board.length, n = board[0].length;

Trie wordTree = new Trie();
for (String word : words) {
wordTree.add(word);
}

Set<String> resultSet = new HashSet<>(); // 注意此处对 board 中的多个相同单词去重
boolean[][] visited = new boolean[m][n];
StringBuilder sb = new StringBuilder();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dfs(resultSet, sb, visited, wordTree, board, i, j);
}
}

return new ArrayList<>(resultSet);
}

private void dfs(Set<String> resultSet, StringBuilder sb, boolean[][] visited, Trie wordTree, char[][] board, int i, int j) {
int m = board.length, n = board[0].length;

if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j] || wordTree == null) {
return;
}

sb.append(board[i][j]);
visited[i][j] = true;

// 注意此处在末尾字符收集,需要走到 Trie 的下个节点才能判断是否为边界
wordTree = wordTree.children[board[i][j] - 'a'];
if (wordTree != null && wordTree.isEnd) {
resultSet.add(sb.toString());
}

for (int[] direction : DIRECTIONS) {
dfs(resultSet, sb, visited, wordTree, board, i + direction[0], j + direction[1]);
}

sb.deleteCharAt(sb.length() - 1);
visited[i][j] = false;
}
}

References

212. Word Search II