面试题12:矩阵中的路径
// 题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有
// 字符的路径。路径可以从矩阵中任意一格开始,每一步可以在矩阵中向左、右、
// 上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入
// 该格子。例如在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字
// 母用下划线标出)。但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个
// 字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
// A B T G
// C F C S
// J D E H
解题思路:
这是一个可以用回溯算法解决的问题。
首先任选一个格子开始走,如果第i次选择的这个格子的字符,恰好对应目标字符串第i个字符,
可以从这个格子的上下左右开始尝试寻找第i+1个字符,找到符合条件的继续往下走,否则就回退上一步。
(边边角角的就没有四个格子,相邻的只有2个或者3个,需要注意判断)
那么什么时候截止呢?当目标字符串的字符为'\0'就说明找到了一条路,函数就可以返回了。
由于题目的要求,进入一个格子后无法再次进入,所以应该有一个bool类型的数组记录已经组走过的路径。
伪代码:
bool hasPath(){
if(参数无效)
return false;
for(每行每列每个格子){
if(存在一条合法路径)
return true;
}
return false;
}
bool hasPathCore(){
if(当前要寻找字符的是'\0')
return true;
if(行列合法&&格子当前字符==目标字符&&当前格子还未进入){
标记此格子已进入;
字符向后移位;
if(上下左右没有条路可以走通){
字符向前回退;
标记此格子未进入;
}
}
return;
}
c/c++:
bool hasPath(const char* matrix, int rows, int cols, const char* str) {
//校验参数有效性
if (matrix == nullptr || rows < 1 || cols < 1 || str == nullptr)
return false;
//标记格子是否被选中,初始化为false
bool* visited = new bool[rows*cols];
memset(visited, 0, rows*cols);
//从第0步,0行0列的格子开始走
int pathLength = 0;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (hasPathCore(matrix, rows, cols, row, col, str, pathLength, visited))
return true;
}
}
//释放标记内存
delete[] visited;
return false;
}
bool hasPathCore(const char* matrix, int rows, int cols, int row, int col,
const char* str, int& pathLength, bool* visited) {
//寻找路径结束
if (str[pathLength] == '\0')
return true;
bool hasPath = false;
//当参数合法
//且目前要走的格子就是要寻找的路径下一步
if (row >= 0 && row < rows&&col >= 0 && col < cols && !visited[cols*row + col]
&& matrix[row*cols + col] == str[pathLength]) {
//假设此路走得通,下一步
//标记此格子已经被选中
++pathLength;
visited[row*cols + col] = true;
//从此格子开始向上下左右寻找可行路径
hasPath = hasPathCore(matrix, rows, cols, row, col - 1, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row, col + 1, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row - 1, col, str, pathLength, visited)
|| hasPathCore(matrix, rows, cols, row + 1, col, str, pathLength, visited);
//此路不通,回退
//标记此格子未被选中
if (!hasPath) {
--pathLength;
visited[row*cols + col] = false;
}
}
return hasPath;
}