题目介绍
力扣79题:leetcode-cn.com/problems/wo…
回溯
- 以
SEE为例,首先要选起点:遍历矩阵,找到起点S。 - 起点可能不止一个,基于其中一个
S,看看能否找出剩下的"EE"路径。 - 下一个字符E有四个可选点:当前点的上、下、左、右。
- 逐个尝试每一种选择。基于当前选择,为下一个字符选点,又有四种选择。
- 每到一个点做的事情是一样的。
DFS往下选点,构建路径。 - 当发现某个选择不对,不用继续选下去了,结束当前递归,考察别的选择。
接着关注当前考察的点,处理它,其他丢给递归子调用去做。判断当前选择的点,本身是不是一个错的点。剩下的字符能否找到路径,交给递归子调用去做。
如果当前点是错的,不用往下递归了,返回false。否则继续递归四个方向,为剩下的字符选点。
那么,哪些情况说明这是一个错的点:
- 当前的点,越出矩阵边界。
- 当前的点,之前访问过,不满足「同一个单元格内的字母不允许被重复使用」。
- 当前的点,不是目标点,比如你想找
E,却来到了D。
代码如下:
class Solution {
public boolean exist(char[][] board, String word) {
// 类似于在二叉树找单链表 不同点在于二叉树只有向下一个方向
// 因此二叉树不需要回溯修改已访问节点
// 但是网格有四个方向,只能上下左右,需要回溯修改节点访问状态
// visited 数组防止重复访问
int m = board.length;
int n = board[0].length;
//存储节点是否被访问过
boolean[][] visited = new boolean[m][n];
// 每个格子都可能是起点
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(board, i, j, 0, word, visited))
return true;
}
}
return false;
}
public boolean dfs(char[][] a, int row, int col, int i, String word, boolean[][] visited) {
// 不在网格内
if (!inArea(a, row, col))
return false;
// 重复访问
if (visited[row][col] == true)
return false;
// 当前字符不等
if (a[row][col] != word.charAt(i))
return false;
//i为当前比较的字符下标,全部字符匹配
if (i == word.length() - 1)
return true;
// 当前字符匹配 做访问标记
visited[row][col] = true;
// 当前点四个方向匹配下一个字符
boolean f = dfs(a, row - 1, col, i + 1, word, visited) ||
dfs(a, row + 1, col, i + 1, word, visited) ||
dfs(a, row, col - 1, i + 1, word, visited) ||
dfs(a, row, col + 1, i + 1, word, visited);
if (f == true)
return true;
//回溯修改当前不能访问的点 但是接下来的方向可以访问它
visited[row][col] = false;
return false;
}
public boolean inArea(char[][] a, int i, int j) {
if (0 <= i && i < a.length && 0 <= j && j < a[0].length)
return true;
return false;
}
}