地上有一个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
解题思路:深度优先遍历
可以从左上角(0,0)开始向下与向右进行深度优先遍历,如果k很小,则在整个二维数组中,机器人可以运动的范围将被分割成几个不连通的部分,但随着k增大,逐渐开始连通,也是从机器人的右边和下边首先开始连通的,所以只用递归下下边和右边就行了。用深度优先遍历从(0,0)开始往右边或下边搜索到底,再返回上一个元素往另一个方向搜索,以此类推。
算法流程:
public:
1.创建标记二维数组flag标记已经走过的位置,并初始化为0
2.返回深度优先遍历函数dfs的返回值
传入(第一个位置的行数0,列数0,flag数组,地图行数m,地图列数n,k)
private:
1.定义dfs函数,传入(当前位置的函数 i,当前位置的列数 j,flag,m,n,k)
如果i>=m(越界)或j>=n(越界)或 i 的个位数+ i 十位数+ j 的个位数+ j的十位数 > k 或flag[i][j]==true(走过了)
返回0
flag[i][j]=1(标记走过的位置为true)
返回 1+递归向下搜索+递归向右搜索
代码:
class Solution {
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> flag(m,vector<bool> (n,0));
return dfs(0,0,flag,m,n,k);
}
private:
int dfs(int i,int j,
vector<vector<bool>> &flag,int m,int n,int k) {
if(i>=m||j>=n||i%10+i/10+j%10+j/10>k||
flag[i][j]) return 0;
flag[i][j]=true;
return 1+dfs(i+1,j,flag,m,n,k)+
dfs(i,j+1,flag,m,n,k);
}
};
解题思路:广度优先遍历
也可以用广度优先遍历从(0,0)开始,把其右边的位置(0,1)与其下边的位置(1,0)入队q,然后(0,0)出队。再队头元素(0,1)出队,再把其右边与下边的位置入队,以此类推。直到队列为空,则说明搜索结束。为了避免重复走过,也需flag标记函数。队列q需要存储位置,所以需要创建数组类型的队列。最后还要一个计数变量count统计可以运动到的位置的数目。
算法流程:
1.创建标记二维数组flag并初始化为0
2.创建数组类型的队列q
3.创建计数遍历count并初始化为0
4.把第一个位置[0,0]入队
5.循环直到队列为空
创建数组arr存储队头元素
队头元素出队
创建遍历 i 存储位置的行数
创建遍历 j 存储位置的列数
创建遍历 a 存储行数的个位数与十位数之和
创建遍历 b 存储列数的个位数与十位数之和
如果行数或列数越界或a+b > k 或flag已走过
跳过本次循环执行下一个循环
count++
标记该位置为true
该位置的下边位置入队
该位置的右边位置入队
6.返回count
代码:
class Solution {
public:
int movingCount(int m, int n, int k) {
vector<vector<bool>> flag(m,vector<bool> (n,0));
queue<vector<int>> q;
int count=0;
q.push({0,0});
while(!q.empty()) {
vector<int> arr=q.front();
q.pop();
int i=arr[0],j=arr[1];
int a=i%10+i/10;
int b=j%10+j/10;
if(i>=m||j>=n||a+b>k||flag[i][j])
continue;
count++;
flag[i][j]=true;
q.push({i+1,j});
q.push({i,j+1});
}
return count;
}
};