题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如\begin{bmatrix} a & b & c &e \\ s & f & c & s \\ a & d & e& e\\ \end{bmatrix} 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路分析
- 将题目所给的一维数组,根据行列数转为二维数组(其实不转也可以,转了更好理解)
- 把每一个格子都当作起点开始寻找,即 path(matrix_2, rows, cols, str, i, j,visit_xy,0) 中的i,j都是循环出来的
- 进入path方法(主要方法):
- 是否已经找到str长度的字符,判断是否为成功出口
- 判断row和col是否合法;判断此次访问的字符数是否已经超过所要判断的字符数;判断当前格是否已经被访问过
- 不合法退出,合法且长度不满足则继续。然后标记当前格;并访问字符数计量+1;判断当前的字符和str的对应字符是否相等,str是需要匹配的字符,不一致证明不需要继续往下走了,字符已经不一样了,一致则可以继续走
- 当前字符一致才继续往下寻找,然后上下左右都递归寻找
- 递归都找不到,就回退,清除当前访问的标记。
代码
/**
*
* @Description:
* 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
* 路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
* 如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
* 例如 [a b c e]
* [s f c s]
* [a d e e]
* 矩阵中包含一条字符串"bcced"的路径,
* 但是矩阵中不包含"abcb"路径,
* 因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
*/
public class HasPath {
/**
* 无用方法
* 用于被main方法调用,然后函数内部调用path函数
* @param matrix 本来是个二维矩阵,函数参数给了个一维矩阵,需转换
* @param rows 行数
* @param cols 列数
* @param str 匹配字符,矩阵中是否存在一条包含该字符串所有字符的路径
* @return
*/
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//存储转换结果
char[][] matrix_2 = new char[rows][cols];
// 一维转换二维矩阵
for(int i = 0; i < rows ; i++)
{
for (int j = 0; j < cols; j++) {
// i * 每行元素数量(即列数) + 第i+1行(即j行)
matrix_2[i][j] = matrix[ i * cols + j];
}
}
//每一个格子都是起点开始寻找
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
/*visit_count 访问的数据数 , 起始为0*/
/*visit_xy标示对应的matrix的格子是否被访问*/
int[][] visit_xy = new int[rows][cols];
boolean path = path(matrix_2, rows, cols, str, i, j,visit_xy,0);
if (path)
{
//有一次成功就直接返回true
return true;
}
}
}
return false;
}
/**
* 在hasPath函数基础上添加了row 和 col,同时标示某一个格子
* @param matrix 已经是二维数组了
* @param rows
* @param cols
* @param str
* @param row 当前行
* @param col 当前列
*@param visit_xy 二维数组每个字符对应是否被访问的表示数组
* @param visit_count 访问的数据数量, 起始为0
* @return
*/
public boolean path(char[][] matrix, int rows, int cols, char[] str,int row ,int col,int[][] visit_xy,int visit_count)
{
// 1.**是否已经找到str长度的字符,成功出口
if(visit_count == str.length)
{
// 长度满足
//进而判断是否一致
boolean flag = true;
//成功出口
return flag;
}
//2.判断row和col是否合法
if (row >= rows || col >= cols || row <0 || col < 0
//2.判断访问数的数量是否越界(判断此次访问的字符数是否已经超过所要判断的字符数);
// 2.判断字符matrix[row,col]是否已经被访问过==已经被在visit_xy中标示了 [visit_xy[row][col] == 1]
|| visit_count > str.length || visit_xy[row][col] == 1)
{
// 不合法
return false;
}
//3.长度不满足,继续递归
//标示为1,代表被访问过了
visit_xy[row][col] = 1;
//先判断当前当前的字符和str的对应字符是否相等
boolean compare = (matrix[row][col]==str[visit_count]);
//已经访问的字符数量+1
visit_count++;
if (compare) {
//字符相等才判断,不等就return false;判断是否字母相同,不同就不继续递归了
//上下右左 胡乱的寻找
if (path(matrix, rows, cols, str, row, col + 1, visit_xy, visit_count) //右
|| path(matrix, rows, cols, str, row + 1, col, visit_xy, visit_count) //下
|| path(matrix, rows, cols, str, row, col - 1, visit_xy, visit_count) //左
|| path(matrix, rows, cols, str, row - 1, col, visit_xy, visit_count))//上
{
return true;
}
}
//失败,回退,清除标记
visit_xy[row][col] = 0;
return false;
}
public static void main(String[] args) {
char[] chars = "ABCESFCSADEE".toCharArray();
/*
A B C E
S F C S
A D E E
A S F D E C C B A
*/
char[] chars1 = "EEDASABCESCF".toCharArray();
boolean b = new HasPath().hasPath(chars, 3, 4, chars1);
System.out.println(b);
}
}