题目描述
地上有一个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。请问该机器人能够到达多少个格子?
解题思路
方法一:广度优先
首先需要一个函数得到某个位置的下标有多少位:
cpp
int Solution::get(int x)
{
int res = 0;
for (; x; x /= 10)
res += x % 10;
return res;
}
通过上面的函数得到某个位置横坐标和纵坐标的位数,来和k比较是否满足题目要求。
广度优先采用队列的方式解决,用一个队列存储满足条件的位置,由于是从左上角(0,0)开始,因此只需要看它的右边和下边即可。将满足条件的点加入到队列中作为下一次需要被查询右边和下边的点。另外用一个二维数组标记已经被访问过的位置,因为向下和向右查找时包含被查询过的点。
当出现x<0或者y<0或者x>=m或者y<=n或者坐标位数和大于k时则跳过该点。
方法二:深度优先
深度优先则需要使用递归。首先需要搞清楚递归返回的条件。什么时候递归返回?当当前访问的横坐标或纵坐标>=m,n的值或者横坐标位数+纵坐标位数>k或者当前节点已经被访问过了(由于是向右和向下两个方向,因此不会出现i/j<0),此时返回0。(返回0而不是false是因为我们需要得到能到达的个数)
在深度优先中涉及到一个-8的操作,这里举例说明:
例如我们现在的i是19,下一次+1则为20,而19对应的位数和是10;但20对应的位数和是2。
代码
方法一:
cpp
int Solution::get(int x)
{
int res = 0;
for (; x; x /= 10)
res += x % 10;
return res;
}
int Solution::movingCount(int m, int n, int k)
{
if (!k)
return 1;
std::queue<std::pair<int, int> > Q;
int dx[2] = { 0, 1 };
int dy[2] = { 1, 0 };
std::vector<std::vector<int> > vis(m, std::vector<int>(n, 0));
Q.push(std::make_pair(0, 0));
vis[0][0] = 1;
int ans = 1;
while (!Q.empty()) {
int x, y;
std::tie(x, y) = Q.front();
Q.pop();
for (int i = 0; i < 2; ++i) {
int tx = dx[i] + x;
int ty = dy[i] + y;
if (tx < 0 || tx >= m || ty < 0 || ty >= n || vis[tx][ty] || get(tx) + get(ty) > k)
continue;
Q.push(std::make_pair(tx, ty));
vis[tx][ty] = 1;
ans++;
}
}
return ans;
}
方法二:
cpp
class Solution {
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> visited(m, vector<bool>(n, false));
return dfs(0, 0, k, visited);
}
private:
int dfs(int i, int j, int k, vector<vector<bool>>& visited) {
if (i >= visited.size() || j >= visited[0].size() || visited[i][j] || getSum(i, j) > k) {
return 0;
}
visited[i][j] = true;
return 1 + dfs(i + 1, j, k, visited) + dfs(i, j + 1, k, visited);
}
int getSum(int i, int j) {
int sum = 0;
while (i > 0) {
sum += i % 10;
i /= 10;
}
while (j > 0) {
sum += j % 10;
j /= 10;
}
return sum;
}
};