参考自:《剑指Offer——名企面试官精讲典型编程题》
题目:机器人的运动范围
地上有一个m行n列的方格。一个机器人从坐标(0, 0)的格子开始移动,它每一次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格(35, 37),因为3+5+3+7=18。但它不能进入方格(35, 38),因为3+5+3+8=19。请问该机器人能够到达多少个格子?
主要思路:主要使用回溯法
。机器人从(0, 0)开始移动,当机器人准备移动到坐标(x,y)时,首先判断该坐标是否满足条件,若满足条件则进入该格子,再判断是否能进入周围相邻的格子。
关键点:回溯法,递归
时间复杂度:O(m*n)
public class MovingCount {
public static void main(String[] args) {
//21
int count = movingCount(5, 10, 10);
System.out.println(count);
//359
int count1 = movingCount(15, 20, 20);
System.out.println(count1);
}
private static int movingCount(int threshold, int rows, int cols) {
if (threshold <= 0 || rows < 1 || cols < 1) {
return 0;
}
boolean[][] visited = new boolean[rows][cols];
return move(threshold, rows, cols, 0, 0, visited);
}
private static int move(int threshold, int rows, int cols,
int row, int col, boolean[][] visited) {
int count = 0;
if (canMove(threshold, rows, cols, row, col, visited)) {
visited[row][col] = true;
//判断是否进入周围相邻格子
count = 1 + move(threshold, rows, cols, row - 1, col, visited)
+ move(threshold, rows, cols, row + 1, col, visited)
+ move(threshold, rows, cols, row, col - 1, visited)
+ move(threshold, rows, cols, row, col + 1, visited);
}
return count;
}
/**
* 判断是否可以到达
*
* @param threshold the threshold
* @param rows the rows
* @param cols the cols
* @param row the row
* @param col the col
* @param visited the visited
* @return boolean
*/
private static boolean canMove(int threshold, int rows, int cols,
int row, int col, boolean[][] visited) {
if (row >= 0 && row < rows && col >= 0 && col < cols
&& !visited[row][col]) {
//行和列的数位之和
int digits = getDigits(row) + getDigits(col);
return digits <= threshold;
}
return false;
}
/**
* 获取数位之和
*
* @param num the num
* @return digits
*/
private static int getDigits(int num) {
int digits = 0;
while (num != 0) {
digits += num % 10;
num /= 10;
}
return digits;
}
}