机器人的运动范围

题目描述

地上有一个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 <= m,n <= 100
  • 0 <= k <= 20

题目链接

Leetcode

题目解答

解法一

深度优先遍历,机器人从坐标[0, 0]开始移动,搜索的时候只需要向下和向右移动就能走完所有符合条件的格子。机器人能到达的格子数,从整体上来看就是当前所在的格子计为1,加上右边相邻格子能到达的格子总数,加上下边相邻格子能到达的格子总数,依次递归就能得到最终的结果。为了避免重复计算,对于已经走过的格子需要修改访问状态,遇到超出方格范围、已经访问过、限制访问的格子递归返回。

时间复杂度:$O(mn)$ 空间复杂度:$O(mn)$

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
class Solution {
public int movingCount(int m, int n, int k) {
boolean[][] visit = new boolean[m][n];
return dfs(m, n, k, 0, 0, visit);
}

public int dfs(int m, int n, int k, int i, int j, boolean[][] visit) {
if (i < 0 || i >= m || j < 0 || j >= n || visit[i][j] || forbid(i, j, k)) {
return 0;
}
visit[i][j] = true;
return 1 + dfs(m, n, k, i + 1, j, visit) + dfs(m, n, k, i, j + 1, visit);
}

public boolean forbid(int i, int j, int k) {
int sum = 0;
while (i > 0 || j > 0) {
sum += i % 10;
sum += j % 10;
i /= 10;
j /= 10;
}
return sum > k;
}
}

执行用时:1 ms, 在所有 Java 提交中击败了85.13%的用户
内存消耗:35.3 MB, 在所有 Java 提交中击败了80.07%的用户

解法二

广度优先遍历,借助队列可以通过迭代的方式访问格子,整体思路与解法一类似,但是访问格子的顺序不太一样,同时队列元素的插入与删除会带来额外的时间开销。

时间复杂度:$O(mn)$ 空间复杂度:$O(mn)$

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
class Solution {
public int movingCount(int m, int n, int k) {
LinkedList<int[]> queue = new LinkedList<>();
boolean[][] visit = new boolean[m][n];
queue.add(new int[]{0, 0});
int count = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] pos = queue.poll();
int r = pos[0], c = pos[1];
if (r < 0 || r >= m || c < 0 || c >= n || visit[r][c] || forbid(r, c, k)) {
continue;
}
visit[r][c] = true;
queue.add(new int[]{r + 1, c});
queue.add(new int[]{r, c + 1});
count++;
}
}
return count;
}

public boolean forbid(int i, int j, int k) {
int sum = 0;
while (i > 0 || j > 0) {
sum += i % 10;
sum += j % 10;
i /= 10;
j /= 10;
}
return sum > k;
}
}

执行用时:6 ms, 在所有 Java 提交中击败了17.10%的用户
内存消耗:37.1 MB, 在所有 Java 提交中击败了13.59%的用户

-------------本文结束 感谢您的阅读-------------

文章对您有帮助,可以打赏一杯咖啡,鼓励我继续创作!