212. Word Search II
题目描述和难度
- 题目描述:
给定一个二维网格 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
组成。
提示:
- 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
- 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。
- 题目难度:困难。
- 英文网址:212. Word Search II 。
- 中文网址:212. 单词搜索 II 。
思路分析
求解关键:使用字典树 + 搜索的方法可以完成。
- 字典树的结点要暴露出来。
参考解答
参考解答1
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Solution {
// 参考资料:
// https://leetcode.com/problems/word-search-ii/discuss/148041/Clean-Java-Code-Trie
// x-1, y
// x, y-1 x, y x, y+1
// x+1,y
private static final int[][] directions = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
private class TrieNode {
private TrieNode[] next;
private boolean isEnd;
private String word;
public TrieNode() {
next = new TrieNode[26];
isEnd = false;
}
}
public List<String> findWords(char[][] board, String[] words) {
List<String> res = new ArrayList<>();
if (words == null || words.length == 0) {
return res;
}
int row = board.length;
if (row == 0) {
return res;
}
int col = board[0].length;
TrieNode root = new TrieNode();
boolean[][] visited = new boolean[row][col];
for (String word : words) {
TrieNode curNode = root;
for (char c : word.toCharArray()) {
if (curNode.next[c - 'a'] == null) {
curNode.next[c - 'a'] = new TrieNode();
}
curNode = curNode.next[c - 'a'];
}
if (!curNode.isEnd) {
curNode.isEnd = true;
curNode.word = word;
}
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
dfs(board, visited, i, j, row, col, root, res);
}
}
// 最后要去重
Set<String> set = new HashSet(res);
res = new ArrayList<>(set);
return res;
}
/**
* @param board 字符面板
* @param visited 记录当前坐标是否被访问过
* @param i 横坐标
* @param j 纵坐标
* @param row 横坐标的最大值
* @param col 纵坐标的最大值
* @param node 当前字典树结点
* @param res 结果集
*/
private void dfs(char[][] board, boolean[][] visited, int i, int j, int row, int col, TrieNode node, List<String> res) {
if (node.isEnd) {
res.add(node.word);
}
if (inArea(i, j, row, col) && !visited[i][j]) {
TrieNode nextNode = node.next[board[i][j] - 'a'];
// 特别注意这个访问的位置
visited[i][j] = true;
if (nextNode != null) {
for (int k = 0; k < 4; k++) {
int newX = i + directions[k][0];
int newY = j + directions[k][1];
dfs(board, visited, newX, newY, row, col, nextNode, res);
}
}
// 特别注意这个访问的位置
visited[i][j] = false;
}
}
private boolean inArea(int i, int j, int row, int col) {
return i >= 0 && i < row && j >= 0 && j < col;
}
public static void main(String[] args) {
String[] words = {"oath", "pea", "eat", "rain"};
char[][] board = {
{'o', 'a', 'a', 'n'},
{'e', 't', 'a', 'e'},
{'i', 'h', 'k', 'r'},
{'i', 'f', 'l', 'v'}};
Solution solution = new Solution();
List<String> solutionWords = solution.findWords(board, words);
System.out.println(solutionWords);
}
}
本篇文章的地址为 https://liweiwei1419.github.io/leetcode-solution/leetcode-0212-word-search-ii ,如果我的题解有错误,或者您有更好的解法,欢迎您告诉我 liweiwei1419@gmail.com 。