0%

剑指offer013机器人的运动范围

Problem:

地上有一个 m 行和 n 列的方格。一个机器人从坐标 (0, 0) 的格子开始移动,每一次只能向左右上下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 k 的格子。

例如,当 k 为 18 时,机器人能够进入方格 (35,37),因为 3+5+3+7=18。但是,它不能进入方格 (35,38),因为 3+5+3+8=19。请问该机器人能够达到多少个格子?

Intuition:

使用深度优先搜索(Depth First Search,DFS)方法进行求解。回溯是深度优先搜索的一种特例,它在一次搜索过程中需要设置一些本次搜索过程的局部状态,并在本次搜索结束之后清除状态。这一题和前面一题比较类似,机器人从坐标(0,0)开始移动,当它准备进入坐标为(i,j)的格子时,通过检查坐标的数位和来判断机器人是否能够进入。如果机器人能够进入坐标为(i,j)的格子,再判断它是否能够进入4个相邻的格子(i,j-1),(i-1,j),(i,j+1),(i+1,j)。设置visited数组的原因是为了避免重复访问导致进入死循环,我们保证如果一个点已经被访问过它就不会再被check了从而保证程序能够在有限时间内退出。

Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class CodingInterview_013 {
public int movingCount(int threshold, int rows, int cols) {
if(threshold <= 0 || rows <= 0 || cols <= 0)
return 0;

boolean[] visitFlags = new boolean[rows * cols]; // 元素是否访问过标识

return movingCountCore(threshold, rows, cols, 0, 0, visitFlags);
}

public int movingCountCore(int threshold, int rows, int cols,
int row, int col, boolean[] visitFlags) {
int count = 0;
// 如果当前元素符合条件,则判断该元素相邻的4个元素
if(check(threshold, rows, cols, row, col, visitFlags)) {
int index = row * cols + col;
visitFlags[index] = true;
count = 1 + movingCountCore(threshold, rows, cols, row, col + 1, visitFlags) +
movingCountCore(threshold, rows, cols, row, col - 1, visitFlags) +
movingCountCore(threshold, rows, cols, row + 1, col, visitFlags) +
movingCountCore(threshold, rows, cols, row - 1, col, visitFlags);
}
return count;
}

// 判断row,col的元素是否符合要求
public boolean check(int threshold, int rows, int cols,
int row, int col, boolean[] visitFlags) {
int index = row * cols + col;
// 索引值在有效范围内、元素尚未访问、各位数和小于等于阈值
if(row >= 0 && row < rows && col >= 0 && col < cols &&
!visitFlags[index] && (getDigitsSum(row) + getDigitsSum(col)) <= threshold ) {
return true;
}
return false;
}

// 计算num的各位数和
public int getDigitsSum(int num) {
if(num <= 0)
return 0;
int sum = 0;
while(num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}

}