剑指 Offer 13. 机器人的运动范围 - Touale Cula's Blog

题目内容

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

 

示例 1:

1
2
输入:m = 2, n = 3, k = 1
输出:3

示例 2:

1
2
输入:m = 3, n = 1, k = 0
输出:1

提示:

1
2
1 <= n,m <= 100
0 <= k <= 20

解法一:深度优先搜索

思路:这道题很像招式_剑指 Offer 12. 矩阵中的路径,所以一开始就是打算套壳

比如:

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
class Solution {
public:

unordered_map <int,unordered_map <int,int>> cmap;
int getNumLength(int num){
int start = 1;
int res = 0;
while(num>start){
res ++;
start *= 10;
}
return res;
}

int caculNum(int num){
int start = pow(10,getNumLength(num));
int res = 0;
while(start >= 1){
res += (num / start % 10);
start /= 10;
}
return res;
}

int cmax(int i,int j){
return i >= j ? i:j;
}

int dfs(int i,int j,int &k,int &m,int &n){

if(i>=m || i<0 || j>= n || j<0 || k< caculNum(i)+caculNum(j) || cmap[i][j] == 1){
return 0;
}
//cout<<i<<" "<<j <<" "<<k<<endl;
cmap[i][j] = 1;
int res = 1 + cmax(max(dfs(i-1,j,k,m,n),dfs(i+1,j,k,m,n)),cmax(dfs(i,j-1,k,m,n),dfs(i,j+1,k,m,n)));
cmap[i][j] = 0;
return res;
}

int movingCount(int m, int n, int k) {

return dfs(0,0,k,m,n);
}
};

但是,发现有个问题,提交后结果总比实际结果要少。
于是构造一个测试用例:

1
2
3
2
3
1

理论上应该是有这三个点

1
2
3
4

0 0 1
1 0 1
0 1 1

在纸上模拟了一下,发现一个问题:
招式_剑指 Offer 12. 矩阵中的路径,这道题不允许后退;但是在这道题是可以后退的,也就是说可以像走迷宫一样自由查找路径,好吧,那就修改一下代码。

修改代码如下:

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
51
52
53
class Solution {
private:
unordered_map <int,unordered_map <int,int>> cmap;

int getNumLength(int num){
int start = 1;
int res = 0;
while(num>start){
res ++;
start *= 10;
}
return res;
}

int caculNum(int num){
int start = pow(10,getNumLength(num));
int res = 0;
while(start >= 1){
res += (num / start % 10);
start /= 10;
}
return res;
}

int dfs(int i,int j,int &k,int &m,int &n){

if(i>=m || i<0 || j>= n || j<0 || k< caculNum(i)+caculNum(j) || cmap[i][j] == 1){
return 0;
}

cmap[i][j] = 1;
int res = 1;

res += dfs(i-1,j,k,m,n);
cmap[i-1][j] = 1;

res += dfs(i+1,j,k,m,n);
cmap[i+1][j] = 1;

res += dfs(i,j-1,k,m,n);
cmap[i][j-1] = 1;

res += dfs(i,j+1,k,m,n);
cmap[i][j+1] = 1;

return res;
}
public:
int movingCount(int m, int n, int k) {

return dfs(0,0,k,m,n);
}
};

也就是说,我在dfs进行了修改,之前是挑选一条能走最远的路:

1
int res =  1 + cmax(max(dfs(i-1,j,k,m,n),dfs(i+1,j,k,m,n)),cmax(dfs(i,j-1,k,m,n),dfs(i,j+1,k,m,n)));

现在变成了每条路都走一下,同时,为了防止走过的路被重复计算,于是加个剪枝:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmap[i][j] = 1;
int res = 1;

res += dfs(i-1,j,k,m,n);
cmap[i-1][j] = 1;

res += dfs(i+1,j,k,m,n);
cmap[i+1][j] = 1;

res += dfs(i,j-1,k,m,n);
cmap[i][j-1] = 1;

res += dfs(i,j+1,k,m,n);
cmap[i][j+1] = 1;

return res;

运行结果,能通过但是不是很理想哎:

1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
16 ms
, 在所有 C++ 提交中击败了
6.23%
的用户
内存消耗:
15.2 MB
, 在所有 C++ 提交中击败了
5.01%
的用户
通过测试用例:
49 / 49

好吧,对caclu这个函数进行改造,用于计算个位十位的加和用

1
2
3
4
5
6
7
int caculNum(int x) {
int res=0;
for (; x; x /= 10) {
res += x % 10;
}
return res;

同时把caculNum的决策放到最后面

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
class Solution {
private:
unordered_map <int,unordered_map <int,int>> cmap;

int caculNum(int x) {
int res=0;
for (; x; x /= 10) {
res += x % 10;
}
return res;
}

int dfs(int i,int j,int &k,int &m,int &n){

if(i>=m || i<0 || j>= n || j<0 || cmap[i][j] == 1) return 0;

if(k<caculNum(i)+caculNum(j)) return 0;

cmap[i][j] = 1;

int res = 1;

res += dfs(i-1,j,k,m,n);
cmap[i-1][j] = 1;

res += dfs(i+1,j,k,m,n);
cmap[i+1][j] = 1;

res += dfs(i,j-1,k,m,n);
cmap[i][j-1] = 1;

res += dfs(i,j+1,k,m,n);
cmap[i][j+1] = 1;

return res;
}
public:
int movingCount(int m, int n, int k) {

return dfs(0,0,k,m,n);
}
};

结果,好像是提升了一点点

1
2
3
4
5
6
7
8
9
10
11
12
执行用时:
8 ms
, 在所有 C++ 提交中击败了
13.00%
的用户
内存消耗:
14.9 MB
, 在所有 C++ 提交中击败了
5.01%
的用户
通过测试用例:
49 / 49

突然发现我是傻逼,dfs应该这样写

1
2
3
4
5
6
int dfs(int i,int j,int &k,int &m,int &n){
if(i>=m || i<0 || j>= n || j<0 || cmap[i][j] == 1 || k<caculNum(i)+caculNum(j)) return 0;
cmap[i][j] = 1;
return 1+dfs(i-1,j,k,m,n)+ dfs(i+1,j,k,m,n)+ dfs(i,j-1,k,m,n)+ dfs(i,j+1,k,m,n);

}