【算法训练】LeetCode#79 单词搜索
一、描述
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true
示例 3:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false
二、思路
深度优先搜索+回溯吧...
三、解题
public class LeetCode79 {
public static void main(String[] args) {
System.out.println(existOne(new char[][]{{'A','B','C','E'},{'S','F','E','S'},{'A','D','E','E'}},"ABCESEEEFS"));
}
// {'A','B','C','E'},
// {'S','F','E','S'},
// {'A','D','E','E'}
public static boolean existOne(char[][] board, String word) {
int m = board.length;
int n= board[0].length;
int targetLen = word.length();
for (int i = 0 ; i < m ; i++){
for (int j = 0 ; j < n ; j++){
if (processOne(board,word,i,j,m,n,0,targetLen,new HashSet<String>())){
return true;
}
}
}
return false;
}
public static boolean processOne(char[][] board,String word,int x,int y,int m,int n,int curLen,int targetLen,HashSet<String> over){
String curLoc = x + String.valueOf(y);
if (x < 0 || y < 0 || x >= m || y >= n || over.contains(curLoc) || curLen + 1 > targetLen){
// 越界了或已遍历或再加一个长度多了
return false;
}
curLen++;
if (curLen == targetLen){
// 长度相等时,判断最后一个是否相等,相等则匹配
return word.charAt(curLen-1) == board[x][y];
}
over.add(curLoc);
if (word.charAt(curLen-1) == board[x][y]){
boolean flag = processOne(board, word, x, y + 1, m, n, curLen, targetLen, over);
if (flag){
over.remove(x + String.valueOf(y+1));
return true;
}
flag = processOne(board, word, x, y - 1, m, n, curLen, targetLen, over);
if (flag){
over.remove(x + String.valueOf(y-1));
return true;
}
flag = processOne(board, word, x + 1, y, m, n, curLen, targetLen, over);
if (flag){
over.remove((x+1) + String.valueOf(y));;
return true;
}
flag = processOne(board, word, x - 1, y, m, n, curLen, targetLen, over);
if (flag){
over.remove((x-1) + String.valueOf(y));
return true;
}
}
over.remove(curLoc);
return false;
}
// 方法二做了一些优化,但是得分还是不高。。。
public static boolean existTwo(char[][] board, String word) {
int m = board.length;
int n= board[0].length;
int targetLen = word.length();
for (int i = 0 ; i < m ; i++){
for (int j = 0 ; j < n ; j++){
if (processTwo(board,new boolean[m][n],i,j,word,0,targetLen)){
return true;
}
}
}
return false;
}
public static boolean processTwo(char[][] board,boolean[][] visited,int i,int j,String target,int k,int targetLen){
if (target.charAt(k) != board[i][j]){
return false; // 如果不等就不用继续了
} else if(k == targetLen-1){
return true; // 比到最后且相等则true,结束条件
}
visited[i][j] = true; // 标记已访问
int[][] directions = {{0,1},{0,-1},{1,0},{-1,0}};
boolean result = false;
for (int[] dir : directions){
int newI = i + dir[0];
int newJ = j + dir[1];
// 模拟上下左右
if (newI >= 0 && newI < board.length && newJ >= 0 && newJ <= board[0].length){
if (!visited[newI][newJ]){
// 且当前路径为访问过
boolean flag = processTwo(board,visited,newI,newJ,target,k+1,targetLen);
if (flag){
// 如果true
result = true;
break;
}
}
}
}
visited[i][j] = false; // 剪枝
return result;
}
}