Description:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 :
a b t g
c f c s
j d e h
矩阵中包含一条字符串"bfce"的路径,但是矩阵中不包含"abfb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
Solution:
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
boolean [][] visited = new boolean[rows][cols]; // 标记每个格子是否已经进入过
int[] pathLength = new int[1]; // 记录当前得到的路径长,初始值为0
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (hasPathCore(matrix, i, j, rows, cols, str, pathLength, visited)) {
return true;
}
}
}
return false;
}
public boolean hasPathCore(char[] matrix, int row, int col, int rows, int cols, char[] str, int[] pathLength, boolean[][] visited) {
if (pathLength[0] == str.length)
return true; // 找到完整路径
boolean hasPath = false;
if (row < rows && row >= 0 && col < cols && col >= 0 &&
str[pathLength[0]] == matrix[row*cols+col] && !visited[row][col]) {
// 当矩阵中坐标为(row, col)的格子和路径字符串中下标为pathLength的字符一样时,
++pathLength[0];
visited[row][col] = true;
// 从四个相邻的格子去定位字符串中下标为pathLength+1的字符
hasPath = hasPathCore(matrix, row, col-1, rows, cols, str, pathLength, visited) ||
hasPathCore(matrix, row-1, col, rows, cols, str, pathLength, visited) ||
hasPathCore(matrix, row, col+1, rows, cols, str, pathLength, visited) ||
hasPathCore(matrix, row+1, col, rows, cols, str, pathLength, visited);
// 找不到路径 -> 回溯
if (!hasPath) {
--pathLength[0];
visited[row][col] = false;
}
}
return hasPath;
}
}
Key Points :
- 由于矩阵中的每个节点都有可能作为路径的起点,所以需要遍历整个矩阵对每个节点作为起点的所有路径做检查。
- 用变量pathLength作为标记计数器,当pathLength的值等于目标路径的长度时,表示能在矩阵中找到目标路径,这是递归的出口。由于Java中基本数据类型只支持值传递,而寻找路径需要递归调用,所以需要传递一个长度为1的数组作为参数。
- 矩阵是一个有界的区域,在检查时需要用row和col的值限制来防止越界。
- 在每个节点移动到下一个节点都考虑向上、向下、向左、向右移动四种情况,只要任一方向能找到当前的目标字符,即认为在当前进度下,目标路径是可能存在的,用hasPath标记。
- 关键的回溯条件是:当前寻找的路径碰到一个节点,无论往什么方向移动都无法找到下一个目标字符,即hasPath == false,回溯需要把pathLength的长度-1,当前访问的位置重新设置为未访问状态(visited[row][col] = false)。