Leetcode之回溯法专题-212. 单词搜索 II(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(前缀树)。
分析:题中提示里写前缀树可以解这题,但我做的时候没看到,硬用回溯+DFS做出来的,时间复杂度很高,二刷的时候再优化吧。
是79题的升级版,同样也是地图题,需要vis数组来控制,具体见79题。
class Solution {
List<String> ans = new ArrayList<>();
int dirx[] = new int[]{0,0,1,-1};
int diry[] = new int[]{1,-1,0,0};
int vis[][] = null;
public List<String> findWords(char[][] board, String[] words) {
vis = new int[board.length][board[0].length]; List<String> list = Arrays.asList(words);
int maxLen = getMaxLen(list);
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if(list.size()!=0){
vis[i][j] = 1;
dfs(board,list,i,j,vis,board[i][j]+"",maxLen);
vis[i][j] = 0;
}
}
} return ans;
} public void dfs(char[][] board,List<String> words,int x,int y,int[][] vis,String now,int maxLen){
if(now.length()>maxLen){
return;
} if(words.contains(now) && !ans.contains(now)){
ans.add(now);
}
if(!hasPrefix(now, words)){
return;
} for(int i=0;i<4;i++){
int xx = x + dirx[i];
int yy = y + diry[i]; if(xx>=0 && xx<board.length && yy>=0 && yy<board[0].length && vis[xx][yy]==0){
vis[xx][yy] = 1; dfs(board,words,xx,yy,vis,now+board[xx][yy],maxLen); vis[xx][yy] = 0;
}
}
} public int getMaxLen(List<String> list){
int max = 0;
if(list.size()==0) return 0;
for (String string : list) {
max = Math.max(max, string.length());
}
return max; } public boolean hasPrefix(String prefix,List<String> list){
int len = prefix.length();
for (String string : list) {
if(string.length()>=len && string.substring(0, len).equals(prefix)){
return true;
}
} return false;
}
}