(一)题目描述
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
(二) 解题思路
该题利用递归+回溯:
1)首先得用一个二重循环遍历二维数组中的每一个数,并以该点作为递归的起始节点
2)编写以board[i][j]为起始节点的回溯+递归函数check(board,str)以此来判断以改点为起始节点能否找到str,可以则返回true,否则返回false。
3)重点是check函数的编写。check函数中我认为的重点如下:
(1)使用二维方向数组int[][] directions={{0,1},{0,-1},{1,0},{-1,0}}来存储遍历的四个方向 (很实用!)
(2)主要思路:主要是使用深度优先遍历:如果当前的board[i][j]==str[k],则向(i,j)的四个方向进行更深层次的遍历:首先是向{0,1}方向,若满足上述条件,则向(i,j+1)的四个方向再进行更深层次的遍历。若某点的四个方向均已经遍历完仍然没有满足条件的值,则回退到(i,j)的上一层,并将(i,j)点标记为false,表明该点未使用过(回溯思想)。result作用:给上层报告此条路能否走通,若能走通,则一路上去均为true,不能走通则一路上去均为false。
(三)代码如下:
class Solution26 {
public boolean exist(char[][] board, String word) {
int rowLen=board.length;
int colLen=board[0].length;
boolean f;//记录当前单词中字母所在位置
boolean[][] flag=new boolean[rowLen][colLen];
for (int i = 0; i <rowLen; i++) {
for (int j = 0; j < colLen; j++) {
//每个board[i][j]位置都要进行一次深度搜索
f=check(board,i,j,word,flag,0);
//如果找到一条可以通的路,则返回true,并不再继续往下找
if(f){
return true;
}
}
}
return false;
}
//总结:涉及二维数组搜索并有方向的,最好定义一个二维数组directions=
public boolean check(char[][] board,int i,int j,String word,boolean[][] flag,int k){
//标记路是否走得通
boolean result = false;
//如果字母不相同,表示此路不通,此时递归会使函数继续找下一个方向的路
if(board[i][j]!=word.charAt(k)){
return false;
}else if(k==word.length()-1){ //board[i][j]==word.charAt(k)的情况下并且是最后一个字母相等
return true;
}
flag[i][j]=true;
//标记四个方向
int[][] directions={{0,1},{0,-1},{1,0},{-1,0}};
for (int[] arr:directions) {
//每一次得到新的方向
int newi=i+arr[0];
int newj=j+arr[1];
if (newi>=0&&newi<board.length&&newj>=0&&newj<board[0].length){
//如果满足以上条件,则进行搜索
//当前这个方向以前没被搜索过
if(!flag[newi][newj]){
//对newi,newj的四个方向进行搜索
boolean b= check(board,newi,newj,word,flag,k+1);
//只有当找到路之后才会返回true,所以此时若进入了if条件,说明已经成功找到路,不需要再继续向其他方向寻找了
if(b){
result=true;
break;
}
}
}
}
//退出for循环后即会执行该两条语句,此时只有两种情况:
// (1)找到路:此时因为break而退出循环,返回的result一路向上退出递归时的返回值必定为true
// (2)未找到路:此时因为不满足循环条件而退出循环,因为result一直为false,所以一路向上退出递归时的返回值必定为false
flag[i][j]=false;
return result;
}
}