给定一个二维网格 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 组成。
这道题目利用字典树进行深搜是可以大大加快效率的。
我们利用字典数来存下words里面的所有单词,在dfs搜索的时候,我们只需要对字典树里的单词
存在的向下检索即可。若不存在可以直接返回。
字典树,不懂的可以学一下,用处挺大的,ac自动机啥的就是字典树的延伸。
class Solution {
public int[] dx={1,-1,0,0};
public int[] dy={0,0,1,-1};
private static class Trie{ //字典树
String word; //单词结束标志,到这里说明已经可以组成一个单词了。
Trie[] next=new Trie[26]; //每个节点都有26个节点
Trie append(char ch){ //拼接字符
if(next[ch-'a']!=null){
return next[ch-'a']; //有则直接返回节点
}
next[ch-'a']=new Trie(); //没有就新建节点
return next[ch-'a'];
}
}
public boolean[][] vis; //判断是否参观过
public List<String> res;
public List<String> findWords(char[][] board, String[] words) {
Trie root=new Trie();
for(String word:words){ //先把单词存入字典树当中
Trie cur=root;
char[] wd=word.toCharArray();
for(char c:wd){
cur=cur.append(c);
}
cur.word=word; //结束标志,说明到这里已经可以组成一个单词
}
res=new ArrayList<String>();
vis=new boolean[board.length][board[0].length];
for(int i=0;i<board.length;++i){ //对board每一个点都进行检索
for(int j=0;j<board[i].length;++j){
dfs(root,i,j,board);
}
}
Collections.sort(res); //需要对结果进行排序
return new ArrayList<String>(res);
}
public void dfs(Trie cur,int x,int y,char[][] board){
if(x<0||y<0||x>=board.length||y>=board[0].length||vis[x][y]){
return;
} //边界返回
cur=cur.next[board[x][y]-'a']; //延伸下一个节点
vis[x][y]=true; //把当前设置为走过 不可重复走
if(cur!=null){ //如果当前不为null的话 可以继续检索
if(cur.word!=null){ //说明到这里已经可以组成一个单词了
res.add(cur.word);
cur.word=null; //变成null是为了防止重复加入单词
}
for(int i=0;i<4;++i){
dfs(cur,x+dx[i],y+dy[i],board); //四个方向检索
}
}
vis[x][y]=false;
}
}