单词搜索IIJava
文章发布较早,内容可能过时,阅读注意甄别。
# 题目
给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。
单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例 1:
输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
输出:["eat","oath"]
示例 2:
输入:board = [["a","b"],["c","d"]], words = ["abcb"]
输出:[]
提示:
- m == board.length
- n == board[i].length
- 1 <= m, n <= 12
- board[i][j] 是一个小写英文字母
- 1 <= words.length <= 3 * 104
- 1 <= words[i].length <= 10
- words[i] 由小写英文字母组成
- words 中的所有字符串互不相同
# 思路
构建字典树,插入数据
# 解法
class Solution {
public List<String> findWords(char[][] board, String[] words) {
//构建字典树
WordTrie myTrie = new WordTrie();
TrieNode root = myTrie.root;
//插入数据
for (String word : words){
myTrie.insert(word);
}
//构建结果集容器
List<String> result = new LinkedList<>();
//矩阵行数
int m = board.length;
//矩阵列数
int n = board[0].length;
//存储该节点是否访问
boolean[][] visited = new boolean[n][m];
//遍历整个二维数组
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
find(board, visited, i, j, m, n, result, root);
}
}
return result;
}
private void find(char[][] board, boolean[][] visited, int i, int j, int m, int n, List<String> result, TrieNode cur) {
//边界判断以及是否已经访问判断
if (i < 0 || i >= m || j < 0 || j >= n || visited[j][i])
return;
//获取子节点状态,判断其是否有子节点
cur = cur.child[board[i][j] - 'a'];
if (cur == null) {
return;
}
//修改节点状态,防止重复访问
visited[j][i] = true;
//找到单词加入
if (cur.isEnd) {
result.add(cur.val);
//找到单词后,修改字典树内叶子节点状态为false,防止出现重复单词
cur.isEnd = false;
}
find(board, visited, i + 1, j, m, n, result, cur);
find(board, visited, i - 1, j, m, n, result, cur);
find(board, visited, i, j + 1, m, n, result, cur);
find(board, visited, i, j - 1, m, n, result, cur);
//最后修改节点状态为未访问状态
visited[j][i] = false;
}
/**
* 字典树
*/
class WordTrie {
//创建根节点
TrieNode root = new TrieNode();
void insert(String s) {
TrieNode cur = root;
for (char c : s.toCharArray()) {
//判断是否存在该字符的节点,不存在则创建
if (cur.child[c - 'a'] == null) {
cur.child[c - 'a'] = new TrieNode();
cur = cur.child[c - 'a'];
} else
cur = cur.child[c - 'a'];
}
//遍历结束后,修改叶子节点的状态,并存储字符串
cur.isEnd = true;
cur.val = s;
}
}
/**
* 字典树节点
*/
class TrieNode {
/**
* 存储最后节点的字符串
*/
String val;
/**
* 根据字符排序,[a,b,c,……,z]
*/
TrieNode[] child = new TrieNode[26];
/**
* 是否是最后叶子节点
*/
boolean isEnd = false;
}
}
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 总结
- 分析出几种情况,然后分别对各个情况实现