题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
题意分析:
题目是指从坐标0,0开始,能够到达的格子数目的总和。可以理解为从坐标0,0开始倒水,谁能够漫过的格子的数目的总和。因为有限制条件的存在,因此水不能漫过所有格子。
要注意题意的理解偏差,不是以下题意:
- 求最长路径,不是求机器人能走到的最长路径
- 求所有路径,不是求机器人有多少种走法
解法:
简单而言,就是广度遍历,并且已经遍历过的格子,可以不遍历。
我们假设有一个方法moveCount(i,j)能够求得从坐标(i,j)开始,能够到达的格子数,那么
moveCount(i,j) = 它四周格子能够到达的格子数 + 1(本身)
另外,不能访问的格子,有三种情况
- 超出边界
- 不满足题目条件k
- 已经计算过,或者说访问过
因此给出递归解法:
import java.util.Stack;
public class Solution {
int movingCount(int threshold, int rows, int cols){
int flag[][] = new int[rows][cols]; //记录是否已经走过
return moveCount(0, 0, rows, cols, flag, threshold);
}
/**
** 计算某个位置开始,能到达多少个格子
**/
private int moveCount(int i, int j, int rows, int cols, int[][] flag, int threshold) {
//超出边界的,不能到达
if (i < 0 || i >= rows || j < 0 || j >= cols){
return 0;
}
//已经到达过的,不能到达
if(flag[i][j] == 1){
return 0;
}
//不满足位置条件的,不能到达
if(numSum(i) + numSum(j) > threshold){
return 0;
}
flag[i][j] = 1;
//对于一个起始点(x,y),它能到达的数目,等于他四个方向能到达数目的和
return moveCount(i - 1, j, rows, cols, flag, threshold)
+ moveCount(i + 1, j, rows, cols, flag, threshold)
+ moveCount(i, j - 1, rows, cols, flag, threshold)
+ moveCount(i, j + 1, rows, cols, flag, threshold)
+ 1;
}
/**
** 计算位置条件
**/
private int numSum(int i) {
int sum = 0;
do{
sum += i%10;
}while((i = i/10) > 0);
return sum;
}
}
非递归算法:
使用栈进行遍历
import java.util.Stack;
public class Solution {
int movingCount(int threshold, int rows, int cols){
if(threshold<0){
return 0;
}
int flag[][] = new int[rows][cols]; //记录是否已经走过
Stack<Integer> stackX = new Stack<Integer>();
Stack<Integer> stackY = new Stack<Integer>();
stackX.push(0);
stackY.push(0);
flag[0][0] = 1;
int count = 1;
while(!stackX.isEmpty()){
int x = stackX.peek();
int y = stackY.peek();
int nextX = 0;
int nextY = 0;
//四个方向
if(isSafe(nextX = x-1,nextY = y,rows, cols, flag,threshold)
|| isSafe(nextX = x+1,nextY = y,rows, cols, flag,threshold)
|| isSafe(nextX = x,nextY = y-1,rows, cols, flag,threshold)
|| isSafe(nextX = x,nextY = y+1,rows, cols, flag,threshold)){
stackX.push(nextX);
stackY.push(nextY);
flag[nextX][nextY] = 1;
count++;
continue;
}
stackX.pop();
stackY.pop();
}
return count;
}
private boolean isSafe(int i, int j, int rows, int cols, int[][] flag, int threshold){
//超出边界的,不能到达
if (i < 0 || i >= rows || j < 0 || j >= cols){
return false;
}
//已经到达过的,不能到达
if(flag[i][j] == 1){
return false;
}
//不满足位置条件的,不能到达
if(numSum(i) + numSum(j) > threshold){
return false;
}
return true;
}
/**
** 计算位置条件
**/
private int numSum(int i) {
int sum = 0;
do{
sum += i%10;
}while((i = i/10) > 0);
return sum;
}
}