题目描述:
地上有一个 rows 行和 cols 列的方格。坐标从 [0,0] 到 [rows-1,cols-1] 。一个机器人从坐标 [0,0] 的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 threshold 的格子。 例如,当 threshold 为 18 时,机器人能够进入方格 [35,37] ,因为 3+5+3+7 = 18。但是,它不能进入方格 [35,38] ,因为 3+5+3+8 = 19 。请问该机器人能够达到多少个格子?
数据范围: 0<=threshold<=15,1<=rows,cols<=100
进阶:空间复杂度 O(nm),时间复杂度 O(nm)
示例1
输入:1,2,3
返回值:3
示例2
输入:0,1,3
返回值:1
示例3
输入:10,1,100
返回值:29
说明:
[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28] 这29种,后面的[0,29],[0,30]以及[0,31]等等是无法到达的
示例4
输入:5,10,10
返回值:21
解法:
思路:
根据DFS,从数组的左上角位置出发,朝一个方向一直查找,直到出现不符合条件的,然后回溯到上一个节点,换个方向继续搜索。对于数组中的每个位置,对它的上下左右都需要进行查找。这里需要的注意的就是:
(1)创建一个新的二维数组,记录数组中每个元素的访问状态。
(2)检查下标,越界直接返回0即可。
(3)检查当前坐标的i, j之和是否大于threshold,如果大于直接返回0。
(4)检查当前元素是否被访问过。
代码:
public class Solution {
int count = 1;
public int movingCount(int threshold, int rows, int cols) {
//用来标记当前位置是否被访问
boolean[][] visited = new boolean[rows][cols];
return dfs(0, 0, threshold, visited);
}
//i j :起始坐标
public int dfs(int i, int j, int threshold, boolean[][] visited){
//越界、该位置被访问,下标之和大于threshold直接返回0
if(i < 0 || i >= visited.length || j < 0 || j >= visited[0].length || threshold < isRange(i, j) || visited[i][j]){
return 0;
}
//表示当前位置被访问
visited[i][j] = true;
//从当前位置的上左下右四个方位分别进行查找
return 1 + dfs(i+1, j, threshold, visited) + dfs(i, j+1, threshold, visited) + dfs(i-1, j, threshold, visited) + dfs(i, j-1, threshold, visited);
}
//计算下标之和
public int isRange(int i, int j){
int sum = 0;
while(i > 0){
sum += i % 10;
i /= 10;
}
while(j > 0){
sum += j % 10;
j /= 10;
}
return sum;
}
}
该代码还可以优化,即:从元素的下和右两个方向进行搜索,而不必从上下左右四个方向都查找。
public class Solution {
int count = 1;
public int movingCount(int threshold, int rows, int cols) {
//用来标记当前位置是否被访问
boolean[][] visited = new boolean[rows][cols];
return dfs(0, 0, threshold, visited);
}
//i j :起始坐标
public int dfs(int i, int j, int threshold, boolean[][] visited){
//越界、该位置被访问,下标之和大于threshold直接返回0
if(i < 0 || i >= visited.length || j < 0 || j >= visited[0].length || threshold < isRange(i, j) || visited[i][j]){
return 0;
}
//表示当前位置被访问
visited[i][j] = true;
//从当前位置的上左下右四个方位分别进行查找
return 1 + dfs(i+1, j, threshold, visited) + dfs(i, j+1, threshold, visited);
}
//计算下标之和
public int isRange(int i, int j){
int sum = 0;
while(i > 0){
sum += i % 10;
i /= 10;
}
while(j > 0){
sum += j % 10;
j /= 10;
}
return sum;
}
}