NO. 1531
地上有一个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
示例 1:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
看题目第一反应,只需要计算横纵坐标和,将和不大于k的值做累加,但其实有个隐藏的坑,就是需要跟原点坐标(0,0)是连通状态。
因此,需要从原点坐标分别向四个方向递归来查看,实际上,也有一个隐藏的优化点,就是其实只需要向XY递增的方向,而不需要向反方向运动:
思路:直接向四个方向递归遍历,使用visit数组来保存访问记录,防止重复递归。
//author: [email protected]
int checkCnt(int** v, int r,int c,int mr,int mc,int k)
{//递归查看
if(!(r < mr && r >= 0 && c < mc && c >= 0) || v[r][c] == 1 || (r%10+r/10+r/100+c/100+c/10+c%10>k))
return 0;
v[r][c] = 1;
return 1+checkCnt(v,r+1,c,mr,mc,k) + checkCnt(v,r-1,c,mr,mc,k) +
checkCnt(v,r,c+1,mr,mc,k) + checkCnt(v,r,c-1,mr,mc,k);
}
int movingCount(int m, int n, int k){
int **visit = (int **)malloc(sizeof(int *) * m);
for (int i = 0; i < m; i++){//动态申请二维数组
visit[i] = (int *)malloc(sizeof(int) * n);
}
return checkCnt(visit,0,0,m,n,k);//返回递归结果
}
思路:使用栈来作为循环的载体代替上面算法的递归,使用列表实现栈省去申请一个3维数组。
//author: [email protected]
typedef struct Node{
int x;
int y;
struct Node * next;
}Stack;//定义链表实现栈,结构体存储xy坐标
int movingCount(int m, int n, int k){
int **visit = (int **)malloc(sizeof(int *) * m);
for (int i = 0; i < m; ++i){//动态申请二维数组
visit[i] = (int *)malloc(sizeof(int) * n);
}
visit[0][0] = 1;
int dx[4] = {1,0,-1,0};//可以只用{1,0}
int dy[4] = {0,1,0,-1};//可以只用{0,1}
Stack* node = (Stack*)malloc(sizeof(Stack));
node->x = 0;
node->y = 0;
node->next = NULL;
int tx,ty,cnt=1;
visit[0][0] = 1;//原点默认已经访问
while(node != NULL){
for(int i=0;i<4;i++){//4个方向
tx = node->x + dx[i];
ty = node->y + dy[i];
if(!(tx < m && tx >= 0 && ty < n && ty >= 0) ||
(visit[tx][ty] == 1) ||
(tx%10+tx/10+tx/100+ty/100+ty/10+ty%10 > k))
continue;
visit[tx][ty] = 1;
Stack* newst = (Stack*)malloc(sizeof(Stack));//新节点申请空间
newst->x = tx;
newst->y = ty;
newst->next = NULL;
newst->next = node->next;//指针后移
node->next = newst;//链表头为最新数据,即实现压栈操作
}
Stack* tmpNode = node;
node=node->next;//踢出队尾元素
free(tmpNode);//释放被踢出元素的空间
cnt++;//出栈时候累加计数
}
return cnt-1;
}
思路:基于解法二,将栈改为队列,使得算法变为广度优先搜索。代码仅有34、35两行不同,代表压栈/入队,其它模块完全一样,即实现了从深度向广度的调整,可见两种算法总是一起拿出来也是有其相似之处。
//author: [email protected]
typedef struct Node{
int x;
int y;
struct Node * next;
}Stack;//定义链表实现队列,结构体存储xy坐标
int movingCount(int m, int n, int k){
int **visit = (int **)malloc(sizeof(int *) * m);
for (int i = 0; i < m; ++i){//动态申请二维数组
visit[i] = (int *)malloc(sizeof(int) * n);
}
visit[0][0] = 1;
int dx[4] = {1,0,-1,0};//可以只用{1,0}
int dy[4] = {0,1,0,-1};//可以只用{0,1}
Stack* node = (Stack*)malloc(sizeof(Stack)), *tailNode;
node->x = 0;
node->y = 0;
node->next = NULL;
tailNode = node;
int tx,ty,cnt=1;
visit[0][0] = 1;//原点默认已经访问
while(node != NULL){
for(int i=0;i<4;i++){//4个方向
tx = node->x + dx[i];
ty = node->y + dy[i];
if(!(tx < m && tx >= 0 && ty < n && ty >= 0) ||
(visit[tx][ty] == 1) ||
(tx%10+tx/10+tx/100+ty/100+ty/10+ty%10 > k))
continue;
visit[tx][ty] = 1;
Stack* newst = (Stack*)malloc(sizeof(Stack));//新节点申请空间
newst->x = tx;
newst->y = ty;
newst->next = NULL;
tailNode->next = newst;//链表尾为最新数据,即实现入队操作
tailNode = tailNode->next;//指针后移
}
Stack* tmpNode = node;
node=node->next;//踢出队尾元素
free(tmpNode);//释放被踢出元素的空间
cnt++;//出栈时候累加计数
}
return cnt-1;
}