给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
输入:
words = ["oath","pea","eat","rain"] and board =
[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
输出: ["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z 组成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 看到题的第一反应是使用一Set存储所有words,以board中每个点开始使用dfs遍历出所有可能的单词,然后判断是否在set中。但是这种方法最大的缺点是不知道单词的长度,因此每遍历一步都需要判断当前单词是否在set中,此外由于不知道单词长度不得不把所有的位置都遍历到。
该问题可以使用前缀树结构替代hashSet,匹配到中间过程若到一个结点没匹配上,则可以直接回溯不需要再往下走了。如下图所示:不妨考虑此时刚好走过 ‘o’ ‘a’ 刚好来到下一个’a’,使用前缀树时此时可以直接回溯到上一步了,但是若时候hashSet时仍需要接着往下走。
实现代码如下:
class Solution {
int[][] directs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public static class Node{
Node[] next;
boolean isEnd;
public Node(){
this.next = new Node[26];
this.isEnd = false;
}
}
Node root = null;
char[][] board;
boolean[][] access;
List<String> result;
public void createTri(String[] words){
this.root = new Node();
for(String word : words){
Node cur = root;
for(int i = 0; i < word.length(); i++){
char c = word.charAt(i);
if(cur.next[c - 'a'] == null){
cur.next[c - 'a'] = new Node();
}
cur = cur.next[c - 'a'];
if(i == word.length() - 1){
cur.isEnd = true;
}
}
}
}
public List<String> findWords(char[][] board, String[] words) {
createTri(words);
this.board = board;
this.access = new boolean[board.length][board[0].length];
this.result = new ArrayList<>();
StringBuilder temp = new StringBuilder();
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
dfs(i, j, root, temp);
}
}
return result;
}
public void dfs(int i, int j, Node cur, StringBuilder temp){
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length ||
access[i][j] || cur.next[board[i][j] - 'a'] == null){
return;
}
cur = cur.next[board[i][j] - 'a'];
access[i][j] = true;
temp.append(board[i][j]);
if(cur.isEnd){
cur.isEnd = false; // 找到一个单词就删一个 防止重复
result.add(temp.toString());
}
for(int[] direct : directs){
dfs(i + direct[0], j + direct[1], cur, temp);
}
temp.deleteCharAt(temp.length() - 1);
access[i][j] = false;
}
}