地上有一个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
解题思路:
运用递归的方法,从第一个数开始,向下或向右运动,每计算一个数将其标记,在之后的递归中不会用到。
递归的三个步骤:
-
终止条件
-
每一层的返回值
-
每一层需要做什么
在本题中,终止条件就是当遍历出界或者纵横左边位数之和大于k或者无法向四周遍历时,即可停止,故停止条件可以写为:
row >= m || col >= n || sum(row) + sum(col) > k || visited[row][col] == 1;
每层的返回值:返回方块个数,遇到停止条件时,返回0。每一层递归都返回符合要求的方块数。
每一层需要做什么:首先判断当前位置是否是终止位置,若不是,将当前visited置一,表示已经计算过当前方块,接着向下方或者向右方计算方块。
代码实现
int sum(int x){ //写一个求位数和的函数
int s = 0;
while (x != 0){
s += x % 10;
x = x / 10;
}
return s;
}
//从0,0开始移动,意味着只会像下或者向右移动,也就是说只要本方格的下面或者右边有符合的x+y<=k即可
int movingsort(int x, int y, int m, int n, int k, int** visit){
//如果数组越界或者索引和大于k或者已经被遍历过,则返回0
if (x >= m || y >= n || sum(x) + sum(y) > k || visit[x][y] == 1 ){
return 0;
}
visit[x][y] = 1; //若没有被遍历过,则将它标记
//向下或向左递归
return movingsort(x + 1, y, m, n, k, visit) + movingsort(x, y + 1, m, n, k, visit) + 1;
}
int movingCount(int m, int n, int k){
int i;
int** visit = (int**)malloc(sizeof(int*) * m); //给标记数组申请内存
for (i = 0; i < m; i++){
visit[i] = (int*)calloc(n, sizeof(int));
}
int count = movingsort(0, 0, m, n, k, visit);
return count;
}
/*
int sum(int x){
int s = 0;
while (x != 0){
s += x % 10;
x = x / 10;
}
return s;
}
int movingCount(int m, int n, int k){
int i, j, count = 0;
int flag[m][n];
for (i = 0; i < m; i++){
for (j = 0; j < n; j++){;
if (i == 0 && j == 0){ //第一个数一定存在,对第一个数进行处理
count++;
flag[i][j] = 1;
}
else if ((i > 0 && flag[i - 1][j] == 1 || j > 0 && flag[i][j - 1] == 1) && sum(i) + sum(j) <= k){
count++;
flag[i][j] = 1;
}
else {
flag[i][j] = 0;
}
}
}
return count;
}