面试题13:机器人的运动范围(C++)
题目地址:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/
题目描述
地上有一个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;
- 从坐标(0,0)出发,通过上下左右移动可到达当前格子。
BFS:广度优先搜索使用队列解决问题,我们将每个还未搜索到的点一次性放入队列中,然后弹出队列的头部元素当作当前遍历的节点。BFS在,若不需要确定当前遍历到具体层数,则模板如下
while(队列queue不为空)
cur = queue.pop()
for 节点 in cur的所有相邻节点:
if 该节点有效且未访问过:
queue.push(该节点)
如果需要确定当前遍历到哪一层,即步数或二叉树的的层数则模板如下
层数level = 0
while(队列queue不为空)
队列中元素个数size = queue.size() //需要向前移动的节点个数
while (size --) {
cur = queue.pop()
for 节点 in cur的所有相邻节点:
if 该节点有效且未被访问过:
queue.push(该节点)
}
层数level ++;
在本题中,我们并不需要记录遍历的层数,只需统计总的遍历多少个点即可,我们使用visited记录一个点是否遍历过。
DFS:深度优先搜索通过递归,先朝着一个方向搜索到底,再回溯至上个节点,沿另一个方向搜索,依次类推。在本题中,我们用数组visited来存储每个元素是否已被访问,一般的时候,我们是从上下左右四个方向行走,但分析本题可发现,从下和右两个方向前行,所以,我们最后使用dfs(x + 1, y, m, n, k) + dfs(x, y + 1, m, n, k) + 1来返回向下和向右走的数目。需要注意的一点是剪枝条件,在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,即可行性剪枝。这里我们剪枝的条件设置为当前节点已被访问或该元素下标溢出,以及行坐标x和列坐标y的数位和(即个位+十位)大于k。
程序源码
BFS
class Solution { public: int visited[100][100]; int step = 0; int movingCount(int m, int n, int k) { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { visited[i][j] = 0; //初始化,所有元素均未访问 } } queue<pair<int,int>> que; que.push({0, 0}); visited[0][0] = 1; //已访问 int dir_x[] = {0, 0, -1, 1}; //x方向坐标 int dir_y[] = {-1, 1, 0, 0}; //y方向坐标 while(!que.empty()) { auto front = que.front(); que.pop(); int x = front.first; int y = front.second; step++; for(int i = 0; i < 4; i++) { int new_x = x + dir_x[i]; int new_y = y + dir_y[i]; if(new_x < 0 || new_y < 0 || visited[new_x][new_y] == 1 || new_x >= m || new_y >= n || (new_x / 10 % 10 + new_x % 10 + new_y / 10 % 10 + new_y % 10) > k) continue; que.push({new_x, new_y}); visited[new_x][new_y] = 1; } } return step; } };
DFS
class Solution { public: int visited[100][100]; int step = 0; int movingCount(int m, int n, int k) { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { visited[i][j] = 0; //未访问 } } return dfs(0, 0, m, n, k); } int dfs(int x, int y, int m, int n, int k) { if(visited[x][y] == 1 || x >= m || y >= n || (x / 10 % 10 + x % 10 + y / 10 % 10 + y % 10) > k) return 0; visited[x][y] = 1; //已访问 step = dfs(x + 1, y, m, n, k) + dfs(x, y + 1, m, n, k) + 1; return step; } };
参考文章