13 机器人的运动范围
1 题目描述
地上有一个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。请问该机器人能够到达多少个格子?
2 题目分析
同样的二维数组的遍历问题,考虑回溯法解决。具体步骤:
1. 创建visited[m][n]数组标记是否访问过;
2. movingCountCore(m, n, k, 0, 0, visited)表示从(0, 0)出发可以到达的格子
3. 用check(m, n, k, row, col, visited)表示能否进入(row,col),能的话标记visited,更新count = 1 + movingCountCore(m,n,k,row-1,col,visited)...上下左右。
4. 返回count
check函数具体实现条件:没有越界,没有被访问,数位和没超过k。
3 代码
public static int movingCount1(int m, int n, int k) {
boolean[][] visited = new boolean[m][n];
return movingCountCore(m, n, 0, 0, k, visited);
}
private static int movingCountCore(int m, int n, int i, int j, int k, boolean[][] visited) {
// 检查当前节点是否可达
int count = 0;
if (check(m, n, i, j, k, visited)) {
visited[i][j] = true;
count = 1 + movingCountCore(m, n, i + 1, j, k, visited)
+ movingCountCore(m, n, i - 1, j, k, visited)
+ movingCountCore(m, n, i, j + 1, k, visited)
+ movingCountCore(m, n, i, j - 1, k, visited);
}
return count;
}
private static boolean check(int m, int n, int i, int j, int k, boolean[][] visited) {
if (i >= 0 && i < m && j >= 0 && j < n && !visited[i][j] && (digitCount(i) + digitCount(j)) <= k) {
return true;
}else
{
return false;
}
}
private static int digitCount(int num) {
int digitCount = 0;
while (num > 0) {
digitCount += num % 10;
num = num / 10;
}
return digitCount;
}
4 优化
在搜索过程中可以将搜索方法缩减为向下和向右,而不必向上和向左,因为随着k的增加,新的区域都可以从上方或左方到达。因此我们可以使用递推的做法来解决该题,即同样使用visited来标记,从左上方开始往下扫描数组进行判断当前节点是否可以从左方或者上方任意一边到达(即visit[i - 1] [j]和visit[i] [j - 1]只要有一个为true)即可。
public static int movingCount(int m, int n, int k) {
if (k == 0) return 1;
boolean[][] visited = new boolean[m][n];
visited[0][0] = true;
int ans = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if ((i == 0 && j == 0) || digitCount(i) + digitCount(j) > k) {
continue;
}
// 边界判断
if (i - 1 >= 0) {
visited[i][j] |= visited[i - 1][j];
}
if (j - 1 >= 0) {
visited[i][j] |= visited[i][j - 1];
}
ans += visited[i][j] ? 1 : 0;
}
}
return ans;
}