题目描述

地上有一个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。请问该机器人能够到达多少个格子?

https://leetcode.cn/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/

题解

从 (0, 0) 点出发,实际上只需要考虑每次往右或往下即可。
因为假设机器人已经到达了 (i, j),那一定是从 (i - 1, j) 或 (i, j - 1) 过来的,对应的 visit = 1,不需要再走回去。

广度优先搜索

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
class Solution {
// 返回 x 的位数之和
int get(int x) {
int sum = 0;
for (; x; x /= 10) sum += x % 10;
return sum;
}
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> visit(m, vector<bool>(n, false));
visit[0][0] = true;
queue<pair<int, int>> q;
q.emplace(0, 0);
int dir[2][2] = {{1, 0}, {0, 1}}; // dir[0] 向右,dir[1] 向下
int ans = 1; // (0, 0) 点
while (!q.empty()) {
auto [x, y] = q.front(); q.pop();
for (int i = 0; i < 2; ++i) {
int nx = x + dir[i][0], ny = y + dir[i][1]; // 下一个坐标点
// 省略了 nx < 0 || ny < 0
if (nx >= m || ny >= n || visit[nx][ny] || get(nx) + get(ny) > k) continue;
visit[nx][ny] = true; // (nx, ny) 可达
q.emplace(nx, ny);
ans++;
}
}
return ans;
}
};

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

深度优先搜索(递归)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
// 返回 x 的位数之和
int get(int x) {
int sum = 0;
for (; x; x /= 10) sum += x % 10;
return sum;
}
// 返回从 (i, j) 点出发可以到达多少格子
int dfs(vector<vector<bool>>& visit, int m, int n, int i, int j, int k) {
// 省略了 i < 0 || j < 0
if (i >= m || j >= n || visit[i][j] || get(i) + get(j) > k) return 0;
visit[i][j] = true;
return 1 + dfs(visit, m, n, i + 1, j, k) + dfs(visit, m, n, i, j + 1, k);
}
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> visit(m, vector<bool>(n, false));
return dfs(visit, m, n, 0, 0, k);
}
};

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

动态规划(迭代遍历)

visit[i][j] = vis[i - 1][j] | vis[i][j - 1]:如果 (i - 1, j) 或 (i, j - 1) 可达,则 (i, j) 可达。

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 {
// 返回 x 的位数之和
int get(int x) {
int res = 0;
for (; x; x /= 10) res += x % 10;
return res;
}
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> visit(m, vector<bool>(n, false));
visit[0][0] = true;
int ans = 1; // (0, 0) 点
// 从 (0, 0) 往右往下遍历
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (visit[i][j] || get(i) + get(j) > k) continue;
// if (i > 0 && visit[i - 1][j]) visit[i][j] = true; // 上面可达,则该点可达
// if (j > 0 && visit[i][j - 1]) visit[i][j] = true; // 左边可达,则该点可达
visit[i][j] = (i > 0 && visit[i - 1][j]) | (j > 0 && visit[i][j - 1]);
ans += visit[i][j]; // 不可达时 visit[i][j] = 0,可达时 visit[i][j] = 1
}
}
return ans;
}
};

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