https://leetcode.cn/problems/word-search-ii/description/?envType=study-plan-v2&envId=top-interview-150
思路:
-
我们可以先将这个单词网格转化成一颗字典树,然后再拿words进行搜索。
-
我们可以先将words装换成字典树,然后在在board中选点看能不能走出一条满足的路径来
对于这两个思路其实差不多,但是1的话如果board太大就很容易超时,而且无用的构建会很多(比如有一个5*5的board,理论一条路径长度应该是25,但是如果words中长的单词都只有5的话我们就根本用不到这么长)。
所以权衡来看第二种思路会更好
思路一(确实会超时):
java
class Trie {
Trie[] children;
boolean isEnd;
public Trie() {
children = new Trie[26];
isEnd = true; // 每个被构造出的节点都是一个单词的结尾
}
}
public List<String> findWords(char[][] board, String[] words) {
boolean[][] signed = new boolean[board.length][board[0].length];
Trie root = new Trie();
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
signed[i][j] = true;
if(root.children[board[i][j] - 'a'] == null) {
root.children[board[i][j] - 'a'] = new Trie();
}
transfer(board, signed, root.children[board[i][j] - 'a'], i, j);
signed[i][j] = false;
}
}
List<String> ans = new ArrayList<>();
for(String word : words) {
if(search(root, word)) {
ans.add(word);
}
}
return ans;
}
public void transfer(char[][] board, boolean[][] signed, Trie root, int x, int y) {
for(int i = 0; i < 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if(xx >= 0 && xx < board.length && yy >= 0 && yy < board[0].length && !signed[xx][yy]) {
signed[xx][yy] = true;
if(root.children[board[xx][yy] - 'a'] == null) root.children[board[xx][yy] - 'a'] = new Trie();
transfer(board, signed, root.children[board[xx][yy] - 'a'], xx, yy);
signed[xx][yy] = false;
}
}
}
思路二:
java
class Trie {
Trie[] children;
String word; // 如果当前节点是不是一个单词的结尾,那么word=这个单词,否则word=""
public Trie() {
children = new Trie[26];
word = "";
}
}
public List<String> findWords(char[][] board, String[] words) {
// 将words构建成字典树
Trie root = new Trie();
for(String word : words) {
add(root, word);
}
boolean[][] signed = new boolean[board.length][board[0].length];
HashSet<String> ans = new HashSet<>();
// 在board中选取点在Tire中走看是否存在路径
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
signed[i][j] = true;
dfs(root, board, signed, ans, i, j);
signed[i][j] = false;
}
}
return new ArrayList<>(ans);
}
public void add(Trie root, String word) {
for(int i = 0; i < word.length(); i++) {
if(root.children[word.charAt(i) - 'a'] == null) {
root.children[word.charAt(i) - 'a'] = new Trie();
}
root = root.children[word.charAt(i) - 'a'];
}
root.word = word;
}
/**
* 深度优先搜索
* @param root 当前节点
* @param board 单词网格
* @param signed 标记数组
* @param ans 答案
* @param x 当前位置x坐标
* @param y 当前位置y坐标
*/
public void dfs(Trie root, char[][] board, boolean[][] signed, HashSet<String> ans, int x, int y) {
if(root == null) return;
if(!Objects.equals(root.word, "")) {
ans.add(root.word);
}
root = root.children[board[x][y] - 'a'];
for(int i = 0; i < 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if(xx >= 0 && xx < board.length && yy >= 0 && yy < board[0].length && !signed[xx][yy]) {
char ch = board[xx][yy];
signed[xx][yy] = true;
dfs(root, board, signed, ans, xx, yy);
signed[xx][yy] = false;
}
}
if (root != null && root.word != "") ans.add(root.word);
}
public boolean search(Trie root, String word) {
for(int i = 0; i < word.length(); i++) {
if(root.children[word.charAt(i) - 'a'] == null) {
return false;
}
root = root.children[word.charAt(i) - 'a'];
}
return "".equals(root.word);
}