Medium | 剑指 Offer 13. 机器人的运动范围 | 矩阵 + DFS递归遍历
剑指 Offer 13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0]
到坐标 [m-1,n-1]
。一个机器人从坐标 [0, 0]
的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
本题通过DFS遍历就就能解决。DFS遍历需要设置一个访问数组标志当前位置是否已经访问过。访问下一个位置时可以用一个4x2的数组来表示上下左右的四个方向int[][] dir = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
如果下一个位置可以访问, 就访问它, 不能访问或者访问过了就遍历下一个位置。
private int[][] dir = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
// 访问标志数组
private boolean[][] visit;
private int row;
private int colume;
// 本题的坐标各个位数之和的最大阈值
private int threshold;
public int movingCount(int m, int n, int k) {
this.row = m;
this.colume = n;
this.threshold = k;
visit = new boolean[m][n];
// 开始暴力DFS遍历,
dfs(0, 0);
int res = 0;
// 此时DFS遍历完成, 所有能够访问的位置已经在visit数组打上了标记, 只需要统计数量即可
for(int i = 0; i < row; i++) {
for (int j = 0; j < colume; j++) {
if (visit[i][j]) {
res++;
}
}
}
return res;
}
// dfs遍历矩阵
public void dfs(int x, int y) {
visit[x][y] = true;
// DFS遍历与当前位置相邻的几个位置, 这里只需要向右和向下即可, 不需要向上和向左, 因为是从左上角出发的
// DFS本身是可以枚举每一种可能情况的
for(int i = 1; i < 3; i++) {
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if (checkCanEntry(newx, newy)) {
dfs(newx, newy);
}
}
}
// 判断是否能够访问:1. 下标是否越界 2. 是否已经访问过 3. 坐标位数之和是否超过阈值
public boolean checkCanEntry(int x, int y) {
return x >= 0 && x < row && y >= 0 && y < colume &&
!visit[x][y] &&
getDigit(x) + getDigit(y) <= threshold;
}
// 求某个数字的各个位数之和
public int getDigit(int x) {
int sum = 0;
while(x != 0) {
sum += x % 10;
x /= 10;
}
return sum;
}