面试题12:矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
思路在书上和代码里面注释的很清楚
代码:
class Solution { public: bool hasPath(const char *matrix, int rows, int cols, const char* str) { if (matrix == nullptr || rows <= 0 || cols <= 0 || str == nullptr) return false; bool *visited = new bool[rows*cols];//一维指针数组 memset(visited, 0, rows * cols);//初始化指针数组 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; } //hasPathCore(初始矩阵,矩阵行数,矩阵列数,行索引,列索引,待查询字符串,查找的路径长度,访问标志矩阵) bool hasPathCore(const char* matrix, int rows, int cols, int row, int col, const char* str, int pathLength, bool* visited) { //当访问到str字符串最后的结束符‘\0’时结束回溯,返回true; if (str[pathLength] == '\0') return true; bool hasPath = false; //满足要求继续查找下一个字符:坐标在边界之内,str字符串中的字符出现在了初始矩阵里,改点未被访问过。 if (row >= 0 && row < rows && col >= 0 && col < cols && matrix[row * cols + col] == str[pathLength] && !visited[row * cols + col]) { //满足要求表示这点已经被访问了,路径长度加1,指向下一个字符,访问标志置为true; ++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 (str[pathLength == '\0']) return true;中结束,并且返回true回到主程序 若路径途中没有符合要求的字符串,则会回溯到上一步pathLength--中重新找下一个字符。 */ if (!hasPath) { --pathLength; visited[row * cols + col] = false; } } return hasPath; } };
更新代码及讲解
DFS具体讲解参考:https://blog.csdn.net/raphealguo/article/details/7560918
bool hasPath(const char* matrix, int rows, int cols, const char* str) { if (matrix == nullptr || str == nullptr || rows <= 0 || cols <= 0) return false; //定义访问矩阵 vector<vector<bool> >visit(rows, vector<bool>(cols, false)); //记录遍历长度,遍历到str最后一位时,说明找到我们需要的字符串了 int pathLength = 0; //按照数组从第一位开始遍历回溯 for (int row=0; row < rows; ++row) { for (int col=0; col < cols; ++col) { //进入DFS判断(row,col)是否是解的一个点 if (DFS(matrix, rows, cols, str, row, col, visit, pathLength)) return true; //程序运行到这,表示从(row,col)出发找不到解,所以换一个节点开始 } } return false; } bool DFS(const char* matrix, int rows, int cols, const char* str, int row, int col, vector<vector<bool> >& visit, int& pathLength) { //回溯终止标志:若遍历到str结尾返回true; if (str[pathLength] == '\0') return true; //当(row,col)是其中一位字符且没有被访问过,则可以从这位开始遍历回溯 if (row >= 0 && row < rows && col >= 0 && col < cols && matrix[row * cols + col] == str[pathLength] && visit[row][col] == false) { //长度加1,访问位置true ++pathLength; visit[row][col] = true; /* 这一位遍历完后,接着按照四个方向找下一位合适的字符, 若由此点开始有满足要求的字符出现,则在这会返回true */ if (DFS(matrix, rows, cols, str, row - 1, col, visit, pathLength) || DFS(matrix, rows, cols, str, row, col + 1, visit, pathLength) || DFS(matrix, rows, cols, str, row + 1, col, visit, pathLength) || DFS(matrix, rows, cols, str, row, col - 1, visit, pathLength)) return true; /* 程序运行到这,表示这一位字符沿四个方向运行下去都没有找到合适的节点序列,所以必须从此点回溯。 回溯之前将其重新设置成未访问,因为它有可能出现在下一次搜索的别的路径中 */ --pathLength; visit[row][col] = false; } //到这里,针对(row,col)这一个点的遍历就结束了,返回true表示本次搜索没有找到解,主程序还得从下一个点入手找解 return false; }