剑指65.矩阵中的路径
思路
考察点:DFS+回溯。
回溯:回溯法非常适合由多个步骤组成的问题,并且每个步骤都有多个选项。通常回溯法适合用递归实现代码。当到达某个节点时,尝试所有可能的选项并在满足条件的前提下递归地抵达下一个节点。
深搜+回溯,深搜的过程其实就是对四个方向的一个递归调用的过程,回溯的话是为了消除某一次递归调用所产生的路径不能匹配模式串所产生的影响要被消除掉,消除的结果就是对这条路径上的每一个位置进行状态初始化,即标记为未被遍历。
☆☆☆☆解法
public class Solution { public boolean hasPath(char[] matrix, int rows, int cols, char[] str) { // 先把牛客上给的条件转化成力扣上的条件 char[][] board = new char[rows][cols]; // 版本1:一维转化为二维矩阵 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = matrix[i*cols + j]; } } // 版本2:一维转化为二维矩阵 /*int index = 0; int x = 0; for (int i = 0; i < matrix.length; i++) { if (index >= cols){ index = 0; x++; } board[x][index] = matrix[i]; index++; }*/ boolean[][] vis = new boolean[board.length][board[0].length]; for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[0].length; j++) { if (find(board,String.valueOf(str),i,j,vis,0)){ return true; } } } return false; } private boolean find(char[][] board,String word,int x, int y,boolean[][] vis,int index){ // 越界处理以及每个方格只能访问一次 if (x < 0 || x >= board.length || y < 0 || y >= board[0].length || vis[x][y]){ return false; } // 匹配到某一位置不满足条件 if (word.charAt(index) != board[x][y]){ return false; } // 匹配成功 if (index == word.length()-1){ return true; } vis[x][y] = true; boolean flag = find(board,word,x+1,y,vis,index+1)|| find(board,word,x-1,y,vis,index+1)|| find(board,word,x,y+1,vis,index+1)|| find(board,word,x,y-1,vis,index+1); vis[x][y] = false; return flag; // 走通的时候不标记标记状态也能通过,但一般不这样 /*if (find(board,word,x+1,y,vis,index+1)|| find(board,word,x-1,y,vis,index+1)|| find(board,word,x,y+1,vis,index+1)|| find(board,word,x,y-1,vis,index+1)){ return true; } vis[x][y] = false;//走到这,说明这一条路不通,还原,再试其他的路径 return false;*/ } }
Note:(2020年9月12日15:01:39)
第一次接触回溯,纠结了一天半,一直想不通为什么匹配成功了,也要把标记状态回溯(走不通,标记状态回溯很容易理解)。
原因:
- 因为只代表此次搜索过程中,该元素已访问过,当初始i j变化时,又开始了另一次搜索过程
- 在DFS过程中,每个单元格会多次被访问的,vis[x][y]=false; 只是要保证在当前匹配方案中不要走回头路。
- 因为是一层一层向下递归来进行字符串匹配的,回溯的时候要“释放“这个单元格。匹配失败或者成功都会执行。
- 匹配成功也需要将true结果一层层返回,直至起始点,以获取匹配成功的结果。
- 还原元素是为了新一轮搜索时,矩阵是完整的
因此,虽然这道题在走通的情况下最后返回时,不清空状态标记也能通过,但通常使用回溯法解决问题。匹配成功与否都要“释放”这个单元格。
参考动画: