1. 题目来源
链接:机器人的运动范围
来源:LeetCode——《剑指-Offer》专项
2. 题目说明
地上有一个 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 :
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
3. 题目解析
方法一:DFS、回溯、bool矩阵
典型 DFS
应用,也就是回溯法,主要以下几点思路:
- 以二维数组中每一个数都作为起点和给定字符串做匹配
- 需要一个和原数组等大小的
bool
型visited
数组用来记录当前位置是否已经被访问过 - 若访问未越界、该点没被访问过、满足数位条件,即该点满足要求,将
bool
数组置位,count
加一记录即可,其它情况直接返回
参见代码如下:
// 执行用时 :464 ms, 在所有 C++ 提交中击败了7.01%的用户
// 内存消耗 :158.5 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int movingCount(int m, int n, int k) {
int tmp = m * n;
vector<bool> visited(tmp, false);
int count = movingCountCore(m, n, k, 0, 0, visited);
return count;
}
int movingCountCore(int m, int n, int k, int row, int col, vector<bool>& visited) {
int count = 0;
if (check(m, n, k, row, col, visited)) {
visited[row * n + col] = true;
count = 1 + movingCountCore(m, n, k, row - 1, col, visited)
+ movingCountCore(m, n, k, row, col - 1, visited)
+ movingCountCore(m, n, k, row + 1, col, visited)
+ movingCountCore(m, n, k, row, col + 1, visited);
}
return count;
}
bool check(int m, int n, int k, int row, int col, vector<bool>& visited) {
if (row >= 0 && row < m && col >= 0 && col < n
&& getDigitSum(row) + getDigitSum(col) <= k
&& !visited[row * n + col])
return true;
return false;
}
int getDigitSum(int number) {
int sum = 0;
while (number > 0) {
sum += number % 10;
number /= 10;
}
return sum;
}
};
方法二:DFS、回溯、代码优化
思路和上面一致,在此上面代码过于冗余,在此对其进行修改。
参见代码如下:
// 执行用时 :0 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :9.6 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int nums = 0;
int movingCount(int m, int n, int k) {
vector<vector <int> > arr(m, vector<int>(n, 0));
if(k == 0)
return 1;
dfs(m, n, k, arr, 0, 0);
return nums;
}
void dfs(int m, int n, int k, vector<vector <int> >& arr, int i, int j){
if(i >= m || j >= n || i < 0 || j < 0)
return;
if(arr[i][j] == 1)
return;
if((i % 10 + i / 10 + j % 10 + j / 10) > k)
return;
arr[i][j] = 1;
nums++;
dfs(m, n, k, arr, i - 1, j);
dfs(m, n, k, arr, i + 1, j);
dfs(m, n, k, arr, i, j - 1);
dfs(m, n, k, arr, i, j + 1);
}
};
方法三:DFS性质、回溯、递归、代码优化
对于这道题来讲,是从 (0, 0)
出发。在广度优先算法 BFS
中,由于可行解的连通性和结构,仅考虑向下和向右的移动方向即可,同理深度优先算法 DFS
。
// 执行用时 :4 ms, 在所有 C++ 提交中击败了91.38%的用户
// 内存消耗 :9.3 MB, 在所有 C++ 提交中击败了100.00%的用户
class Solution {
public:
int nums = 0;
int movingCount(int m, int n, int k) {
vector<vector <int> > arr(m, vector<int>(n, 0));
if(k == 0)
return 1;
dfs(m, n, k, arr, 0, 0);
return nums;
}
void dfs(int m, int n, int k, vector<vector <int> >& arr, int i, int j){
if(i >= m || j >= n || i < 0 || j < 0)
return;
if(arr[i][j] == 1)
return;
if((i % 10 + i / 10 + j % 10 + j / 10) > k)
return;
arr[i][j] = 1;
nums++;
dfs(m, n, k, arr, i + 1, j);
dfs(m, n, k, arr, i, j + 1);
}
};