题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
示例 1:
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
提交的代码
参考这个视频
https://www.bilibili.com/video/BV1ZK4y1b7Xn?p=10
public class ArrayPath {
public static void main(String[] args) {
char[][]board={{'a','b','c','d'},
{'g','f','g','h'},
{'i','j','i','l'},
{'e','n','o','p'}};
String word="bfgie";
System.out.println(exist(board, word));
// char[][]board={{'a','b'},{'c','d'}};
// Solution sl=new Solution();
// System.out.println(sl.exist(board, "ojf"));
}
static boolean exist(char[][]board,String word)
{
for(int i=0;i<board.length;i++)
{
for(int j=0;j<board[0].length;j++)
{
if(dfs(board,word,0,i,j))
return true;
}
}
return false;
}
static boolean dfs(char[][]board,String word,int u,int x,int y)
{
//先判断下标,后判断元素
if(x<0||x>board.length-1||y<0||y>board[0].length-1||board[x][y]!=word.charAt(u))
{
return false;//数组越界或者没有找到word中的相应的字符就返回false
}
if(u==word.length()-1)//表示已经查找到word的最后一个字符,说明整个字符串都被找到,刚传进来时u是0,所以不可能进来就返回
{
return true;
}
char temp=board[x][y];
board[x][y]='*';//用过的字符就做一个标记,下次不再使用,因为前面已经判断过board[x][y]=word.charAt(u),说明此时的board[x][y]符合要求
boolean res=dfs(board,word,u+1,x-1,y)
|| dfs(board,word,u+1,x+1,y)
||dfs(board,word,u+1,x,y+1)
||dfs(board,word,u+1,x,y-1);
board[x][y]=temp;//每回溯完一次要把board[x][y]还原
/*
递归搜索匹配字符串过程中,需要 board[i][j] = '*' 来防止 ”
走回头路“ 。当匹配字符串不成功时,会回溯返回,此时需要
board[i][j] = tmp 来”取消对此单元格的标记”。 在DFS过程中
,每个单元格会多次被访问的, board[i][j] = '*'只是要保证在
当前匹配方案中不要走回头路。
*/
return res;
}
}
/*
整个代码的执行流程是首先在二维数组中遍历找到word的第一个字符对应的i,j,先传进来dfs(board,word,0,i,j)
注意,这是考虑了二维数组中有多个word的第一个字符的情况的,只是当其中一种能够不满足时,就接着找下一组
当其中一组满足时,就return true,如果二维数组遍历完,没有找到合适的路径,则返回false
dfs(board,word,0,i,j),进来先判断边界条件,以及board[x][y]==word.charAt(u)),刚开始进来的时候肯定是满足这个条件的
在我看来,这些限制条件都是给递归设定的出口
当满足边界条件以及board[x][y]==word.charAt(u)),接下来就是判断现在的u是否达到word的最后一个字符
如果是,则说明整个字符串被找到,返回true,如果不是,说明我们还需要接着找,先把当前的这个点做一个标记,
因为题目限定如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子
接着找就有上下左右查找4种选择,或运算||的规则是其中一个条件满足就返回true
*/
自己写的有错的代码
import java.util.HashMap;
import java.util.Map;
public class pathInArray {
public static void main(String[] args) {
char[][]board={{'a','b','c','d'},
{'e','f','g','h'},
{'i','j','k','l'},
{'m','n','o','p'}};
// char[][]board={{'a','b'},{'c','d'}};
Solution sl=new Solution();
System.out.println(sl.exist(board, "ojf"));
}
}
class Solution {
int cur_row=0;//全局变量,记录假如查找到word中的一个字符之后,行的位置
int cur_col=0;//全局变量,记录假如查找到word中的一个字符之后,列的位置
char c=' ';//全局变量,用来判断每次dfs返回的值
int [][]assist_board;//辅助矩阵标记用过的格子
int count_f=0;
char a;
public boolean exist(char[][] board, String word) {
int i = board.length;
int j = board[0].length;
assist_board=new int [i][j];//初始化
int word_length = word.length();
HashMap<Integer, Integer> positionOfFirstChar = new HashMap<>();//存放第一个字符在矩阵中的位置
if (i == 0)
return false;
//先找到第一个字符在矩阵中的位置
for (int m = 0; m < i; m++) {
for (int n = 0; n < j; n++) {
if (board[m][n] == word.charAt(0)) {
positionOfFirstChar.put(m, n);
}
}
}
if (positionOfFirstChar.isEmpty()) {
return false;//连第一个字符都没有,返回false
}
for (Map.Entry<Integer, Integer> entry : positionOfFirstChar.entrySet()) {//遍历第一个字符的位置,其中一种情况能够满足找到出入的字符,就break
for (int p = 0; p < word_length - 1; p++) {
// char ac=word.charAt(p);
a=dfs(board, entry.getKey(), entry.getValue(), word.charAt(p), word.charAt(p + 1));//传入指针当前位置,p是已经查找到的字符
//q是p的下一个字符
if(a=='f')
{
count_f++;
break;
}
}
if(count_f==0)
{
return true;
}
// return true;//第一个字符所在位置的其中一种情况满足就返回true,都不满足则返回false
}
return false;
}
// for(int m=0;m<i;m++)
// {
//
// for(int n=0;n<j;n++)
// {
//
// }
// }
//return false;
char dfs(char[][] board,int i,int j,char p,char q)
{
int board_row=board.length;
int board_col=board[0].length;
// if(board[i][j]==p&&assist_board[i][j]==0)//查找到指定字符,且该点还没有用过
// {
// assist_board[i][j]=1;//一旦用过,就置1,默认是0
// cur_row=i;
// cur_col=j;
// // return true;
// }
if(board[i][j]==q&&assist_board[i][j]==0)//查找到指定字符,且该点还没有用过
{
assist_board[i][j]=1;//一旦用过,就置1,默认是0
cur_row=i;
cur_col=j;
return 'o';
}
if(c!=q)
{
return 'a';
}
if(i-1>=0&&i-1<=board_row-1&&j>=0&&j<=board_col-1&&assist_board[i-1][j]!=1)//向上找
{
c=dfs( board, i-1,j, p,q);
}
if(i+1>=0&&i+1<=board_row-1&&j>=0&&j<=board_col-1&&assist_board[i+1][j]!=1)//向下找
{
c= dfs( board, i+1,j, p,q);
}
if(i>=0&&i<=board_row-1&&j+1>=0&&j+1<=board_col-1&&assist_board[i][j+1]!=1)//向右找
{
c= dfs( board, i,j+1, p,q);
}
if(i>=0&&i<=board_row-1&&j-1>=0&&j-1<=board_col-1&&assist_board[i][j-1]!=1)//向左找
{
c=dfs( board, i,j-1, p,q);
}
// else
// return false;
if (c!=q)
{
return 'f'; //表示找到了q,且q在p的上下左右其中一个位置
}
else
return 'o';
}
}
//怎么保证连续呢,就是查找abc的话,先查找到a要保证b出现在a的上下左右方位其中一个呀?
//想法:传参的时候就把a的下一个字符也传进去
//应该先遍历矩阵,找到第一个字符所在的位置,如果有重复,可以用Map来存