剑指 Offer 12. 矩阵中的路径
DFS
思路 🤔
- 遍历矩阵中所有元素:若矩阵中当前元素
board[i][j]
和word.charAt(0)
相等时,尝试使用dfs
进行判断 - 由于是只有找到一个符合条件的,即可。满足条件时,则可以直接返回,所以可以将
dfs
设置为带有返回值boolean dfs(StringBuilder cnt, int x, int y, int index)
; - 每次
dfs
判断当前位置(x, y)
上、下、左、右 四个方法对应的新位置(xx, yy)
- 若新位置越界(预防污染的写法)、新位置已经访问过、新位置元素和
word.charAt(index + 1)
不相等,则跳过; - 否则,则使用新位置
(xx, yy)
继续进行dfs
- 若新位置越界(预防污染的写法)、新位置已经访问过、新位置元素和
class Solution {
int m;
int n;
String word;
char[][] board;
boolean[][] visited;
int[] dirx = {-1, 1, 0, 0};
int[] diry = {0, 0, -1, 1};
public boolean exist(char[][] board, String word) {
this.word = word;
this.board = board;
this.m = board.length;
this.n = board[0].length;
this.visited = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 矩阵中当前元素和word开头元素相等时,尝试使用dfs判断
if (board[i][j] == word.charAt(0)) {
visited[i][j] = true;
if (dfs(new StringBuilder(word.charAt(0)).append(word.charAt(0)), i, j, 1)) {
return true;
}
visited[i][j] = false; // 回溯
}
}
}
return false;
}
boolean dfs(StringBuilder cnt, int x, int y, int index) {
if (cnt.toString().equals(word)) {
return true;
}
// 剪枝
if (index > word.length()) {
return false;
}
for (int i = 0; i < 4; i++) {
int xx = x + dirx[i];
int yy = y + diry[i];
// 新位置越界(预防污染的写法)
if (xx < 0 || xx >= m || yy < 0 || yy >= n) {
continue;
}
// 新位置已经访问过
if (visited[xx][yy]) {
continue;
}
// 新位置元素和word[index + 1]不相等
if ((index + 1) < word.length() && board[xx][yy] != word.charAt(index)) {
continue;
}
visited[xx][yy] = true;
cnt.append(board[xx][yy]);
if (dfs(cnt, xx, yy, index + 1)) {
return true;
}
cnt.deleteCharAt(cnt.length() - 1); // 回溯
visited[xx][yy] = false;
}
return cnt.equals(word);
}
public static void main(String[] args) {
char[][] board = {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}};
String word = "ABCCED";
System.out.println(new Solution().exist(board, word));
StringBuilder sb = new StringBuilder("ABCCED");
System.out.println(sb.equals(word));
System.out.println(word.equals(sb));
}
}
剑指 Offer 13. 机器人的运动范围
提示:
- 1 < = n , m < = 100 1 <= n,m <= 100 1<=n,m<=100
- 0 < = k < = 20 0 <= k <= 20 0<=k<=20
DFS
思路 🤔
- 记
res
为最终所求结果,并初始化int res = 1;
(因为 k > = 0 k>=0 k>=0时 ( 0 , 0 ) (0, 0) (0,0) 一定符合题意); - 每次
dfs
判断当前位置(x, y)
上、下、左、右 四个方法对应的新位置(xx, yy)
- 若新位置越界(预防污染的写法)、新位置已经访问过、新位置元素已经不在满足题意,则跳过;
- 否则,则说明找到了下一个符合题意的位置,则
res++;
,并使用新位置(xx, yy)
继续进行dfs
。
class Solution {
int m;
int n;
int k;
int res = 1; // 第一个元素访问过,即 k>=0时 (0, 0) 一定符合题意。
boolean[][] visited;
int[] dirx = {-1, 1, 0, 0};
int[] diry = {0, 0, -1, 1};
public int movingCount(int m, int n, int k) {
if (k < 0) return 0;
this.k = k;
this.m = m;
this.n = n;
this.visited = new boolean[m][n];
// 第一个元素访问过
visited[0][0] = true;
dfs(0, 0);
return res;
}
void dfs(int x, int y) {
for (int i = 0; i < 4; i++) {
int xx = x + dirx[i];
int yy = y + diry[i];
// 新位置越界(预防污染的写法)
if (xx < 0 || xx >= m || yy < 0 || yy >= n) {
continue;
}
// 新位置已经访问过
if (visited[xx][yy]) {
continue;
}
// 新位置不满足题意
if (getSum(xx) + getSum(yy) > k) {
continue;
}
res++;
visited[xx][yy] = true;
dfs(xx, yy);
// visited[xx][yy] = false; // 这里不回溯
}
}
int getSum(int num) {
int sum = 0;
while (num > 0) {
sum += (num % 10);
num /= 10;
}
return sum;
}
}