一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
题目:给定一个m行n列的网格,网格的坐标从[0, 0]到[m-1, n-1]。现有一个人从[0, 0]开始移动,每次可以上下左右移动一格,但不能越界,也不能进入行坐标和列坐标数位之和大于k的格子,例如,当k的值为18时,机器人可以进入网格[35, 37]但不能进入[35, 38],问最终机器人可以到达多少格子?
解题思路
看完题目随便模拟了一下,例如m=2和n=1的情况,此时k=1,则可到达网格为:
| √ | √ | X |
|---|---|---|
| √ | X | X |
根据上面的思路,这题不就是找出网格内所有网格中符合数位和不大于k的网格吗,于是可得如下代码:
public int movingCount(int m, int n, int k) {
int count = 0;
for(int i=0;i<m;i++){
int inneri = innerSum(i);
for(int j=0;j<n;j++){
int innerj = innerSum(j);
if((inneri+innerj)>k) continue;
count++;
}
}
return count;
}
public int innerSum(int i){
int p = i/100;
int q = (i%100)/10;
int r = i%10;
return p+q+r;
}
很明显,题意理解错误!。。。。。。而之所以出现这个情况,是因为我们默认所有解都是可达的,但事实并不是所有解都可达,例如下面这幅图:
可以看到黄色区域就算满足条件也是不可达的,而上述计算时没有考虑这些,再看下面这幅图:
图片来源: 剑指 Offer 13. 机器人的运动范围( 回溯算法,DFS / BFS ,清晰图解)
有些不可达解转变成了可达解,而我们可以发现一个规律,如果一个网格是可达的,那么从这个网格向下和向右搜索,必然可以搜索到所有满足条件的解,而当遇到了不满足条件的解就不会继续向下或向右搜索,此时就避免计算哪些不可达解了,代码如下:
public int movingCount(int m, int n, int k) {
boolean[][] visited = new boolean[m][n];
return dfs(0, 0, m, n, visited, k);
}
public int innerSum(int i){
int p = i/100;
int q = (i%100)/10;
int r = i%10;
return p+q+r;
}
public int dfs(int i, int j, int m, int n, boolean[][] visited, int k){
if(i>=m||j>=n||(innerSum(i)+innerSum(j)>k)||visited[i][j]) return 0;
visited[i][j] = true;
return 1+dfs(i+1, j, m, n, visited, k)+dfs(i, j+1, m, n, visited, k);
}