Leetcode刷题笔记——剑指 Offer 13. 机器人的运动范围(中等)
文章目录
- 题目描述
- 解题思路
- 方法一:深度优先遍历DFS
- 复杂度分析
- C++代码实现
- 方法二:广度优先遍历BFS
- 复杂度分析
- C++代码实现
- 参考连接
题目描述
地上有一个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。请问该机器人能够到达多少个格子?
解题思路
本题与 矩阵中的路径 类似,是典型的搜索 & 回溯问题。该题的两项前置工作为: 数位之和计算 、 可达解分析 。
数位之和计算:
设一数字 x x x ,向下取整除法符号 / / // // ,求余符号 ⊙ \odot ⊙,则有:
- x ⊙ 10 x \odot 10 x⊙10 :得到 x x x 的个位数字;
- x / / 10 x // 10 x//10 : 令 x x x 的十进制数向右移动一位,即删除个位数字。
因此,可通过循环求得数位和 s s s ,数位和计算的封装函数如下所示:
int sums(int x){int s = 0;while(x != 0) {s += x % 10;x = x / 10;}return s;
}
由于机器人每次只能移动一格(即只能从 x x x 运动至 x ± 1 x \pm 1 x±1),因此每次只需计算 x x x 到 x ± 1 x \pm 1 x±1 的数位和增量。本题说明 1 ≤ n 1 \leq n 1≤n, m ≤ 100 m \leq 100 m≤100 ,以下公式仅在此范围适用。
数位和增量公式: 设 x x x 的数位和为 s x s_x sx , x + 1 x+1 x+1 的数位和为 s x + 1 s_{x+1} sx+1 ;
- 当 ( x + 1 ) ⊙ 10 = 0 (x + 1) \odot 10 = 0 (x+1)⊙10=0 时: s x + 1 = s x − 8 s_{x+1} = s_x - 8 sx+1=sx−8,例如 19 , 20 19, 20 19,20 的数位和分别为 10 , 2 10, 2 10,2 ;
- 当 ( x + 1 ) ⊙ 10 ≠ 0 (x + 1) \odot 10 \neq 0 (x+1)⊙10=0 时: s x + 1 = s x + 1 s_{x+1} = s_x + 1 sx+1=sx+1 ,例如 1 , 2 1, 2 1,2 的数位和分别为 1 , 2 1, 2 1,2 。
可达解分析:
根据数位和增量公式得知,数位和每逢 进位 突变一次。根据此特点,矩阵中 满足数位和的解 构成的几何形状形如多个 等腰直角三角形 ,每个三角形的直角顶点位于 0 , 10 , 20 , . . . 0, 10, 20, ... 0,10,20,... 等数位和突变的矩阵索引处 。
三角形内的解虽然都满足数位和要求,但由于机器人每步只能走一个单元格,而三角形间不一定是连通的,因此机器人不一定能到达,称之为 不可达解 ;同理,可到达的解称为 可达解
根据可达解的结构和连通性,易推出机器人可 仅通过向右和向下移动,访问所有可达解 。
- 三角形内部: 全部连通,易证;
- 两三角形连通处: 若某三角形内的解为可达解,则必与其左边或上边的三角形连通(即相交),即机器人必可从左边或上边走进此三角形。
方法一:深度优先遍历DFS
- 深度优先搜索: 可以理解为暴力法模拟机器人在矩阵中的所有路径。DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
- 剪枝: 在搜索中,遇到数位和超出目标值、此元素已访问,则应立即返回,称之为 可行性剪枝 。
算法解析:
递归参数: 当前元素在矩阵中的行列索引 i i i 和 j j j ,两者的数位和 s i si si, s j sj sj 。
终止条件: 当 ① ① ① 行列索引越界 或 ② ② ② 数位和超出目标值 k k k 或 ③ ③ ③ 当前元素已访问过时,返回 0 0 0 ,代表不计入可达解。
递推工作:
1.标记当前单元格:将索引 ( i , j ) (i, j) (i,j) 存入 visited 中,代表此单元格已被访问过。
2.搜索下一单元格: 计算当前元素的 下、右 两个方向元素的数位和,并开启下层递归。回溯返回值: 返回 1 + 右方搜索的可达解总数 + 下方搜索的可达解总数,代表从本单元格递归搜索的可达解总数。
复杂度分析
- 时间复杂度 O ( M N ) O(MN) O(MN) : 最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为 O ( M N ) O(MN) O(MN)。
- 空间复杂度 O ( M N ) O(MN) O(MN) : 最差情况下,visited 内存储矩阵所有单元格的索引,使用 O ( M N ) O(MN) O(MN) 的额外空间。
C++代码实现
class Solution {public:int movingCount(int m, int n, int k) {vector<vector<bool>> visited(m, vector<bool>(n, 0));return dfs(0, 0, 0, 0, visited, m, n, k);}
private:int dfs(int i, int j, int si, int sj, vector<vector<bool>> &visited, int m, int n, int k) {// 如果不符合条件则直接返回0if(i >= m || j >= n || k < si + sj || visited[i][j]) return 0;// 该位置被访问并记录visited[i][j] = true;// 向下和向右进行搜索return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj, visited, m, n, k) +dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8, visited, m, n, k);}
};
方法二:广度优先遍历BFS
- BFS/DFS: 两者目标都是遍历整个矩阵,不同点在于搜索顺序不同。DFS 是朝一个方向走到底,再回退,以此类推;BFS 则是按照“平推”的方式向前搜索。
- BFS 实现: 通常利用队列实现广度优先遍历。
算法解析:
- 初始化: 将机器人初始点 ( 0 , 0 ) (0, 0) (0,0) 加入队列 q u e u e queue queue ;
- 迭代终止条件: q u e u e queue queue 为空。代表已遍历完所有可达解。
- 迭代工作:
1.单元格出队: 将队首单元格的 索引、数位和 弹出,作为当前搜索单元格。
2.判断是否跳过: 若 ① ① ① 行列索引越界 或 ② ② ② 数位和超出目标值 k k k 或 ③ ③ ③ 当前元素已访问过 时,执行 c o n t i n u e continue continue 。
3.**标记当前单元格 :**将单元格索引 ( i , j ) (i, j) (i,j) 存入 visited 中,代表此单元格 已被访问过 。
4.单元格入队: 将当前元素的 下方、右方 单元格的 索引、数位和 加入 q u e u e queue queue 。 - 返回值: visited 的长度 len(visited) ,即可达解的数量。
复杂度分析
- 时间复杂度 O ( M N ) O(MN) O(MN): 最差情况下,机器人遍历矩阵所有单元格,此时时间复杂度为 O ( M N ) O(MN) O(MN) 。
- 空间复杂度 O ( M N ) O(MN) O(MN): 最差情况下,visited 内存储矩阵所有单元格的索引,使用 O ( M N ) O(MN) O(MN) 的额外空间。
C++代码实现
class Solution {public:int movingCount(int m, int n, int k) {vector<vector<bool>> visited(m, vector<bool>(n, 0));int res = 0;queue<vector<int>> que;que.push({ 0, 0, 0, 0 });while(que.size() > 0) {vector<int> x = que.front();que.pop();int i = x[0], j = x[1], si = x[2], sj = x[3];if(i >= m || j >= n || k < si + sj || visited[i][j]) continue;visited[i][j] = true;res++;que.push({ i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj });que.push({ i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8 });}return res;}
};
参考连接
[1] https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/mian-shi-ti-13-ji-qi-ren-de-yun-dong-fan-wei-dfs-b/
Leetcode刷题笔记——剑指 Offer 13. 机器人的运动范围(中等)相关推荐
- leetcode刷题笔记——剑指offer(二)[回溯、排序、位运算、数学、字符串]
这里写目录标题 搜索与回溯 剑指 Offer 12. 矩阵中的路径 剑指 Offer 13. 机器人的运动范围 剑指 Offer 34. 二叉树中和为某一值的路径 剑指 Offer 36. 二叉搜索树 ...
- Leetcode刷题笔记——剑指offer II (六)【图】
文章目录 图 695. 岛屿的最大面积 剑指 Offer II 106. 二分图 (每条边的两个结点都来自不同的集合) 剑指 Offer II 107. 矩阵中的距离 (最短路问题,建图,BFS) 剑 ...
- Leetcode刷题笔记——剑指offer II (一)【整数、数组、字符串、链表】
目录 整数 剑指 Offer II 001. 整数除法 剑指 Offer II 002. 二进制加法 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 剑指 Offer II 00 ...
- Leetcode刷题笔记——剑指offer II (五)【二分、排序、回溯】
这里写目录标题 二分查找 剑指 Offer II 069. 山峰数组的顶部 剑指 Offer II 070. 排序数组中只出现一次的数字 剑指 Offer II 071. 按权重生成随机数 剑指 Of ...
- Leetcode刷题笔记——剑指 Offer 46. 把数字翻译成字符串(中等)
文章目录 题目描述 解法:动态规划 方法一:字符串遍历 复杂度分析 C++代码实现 方法二:数字求余 复杂度分析 C++代码实现 参考链接 题目描述 给定一个数字,我们按照如下规则把它翻译为字符串:0 ...
- 【LeetCode】剑指 Offer 13. 机器人的运动范围
[LeetCode]剑指 Offer 13. 机器人的运动范围 文章目录 [LeetCode]剑指 Offer 13. 机器人的运动范围 package offer;public class Solu ...
- LeetCode 剑指Offer 13 机器人的运动范围
LeetCode 剑指Offer 13 机器人的运动范围 题目 解题 解题一:深度优先搜索 解题二:广度优先搜索 解题三:动态规划 题目 解题 深度优先和广度优先解题思路参考: 剑指 Offer 13 ...
- 剑指 Offer 13. 机器人的运动范围
剑指 Offer 13. 机器人的运动范围 题目 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] .一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左.右.上 ...
- [[EVD]] - 剑指 Offer 13. 机器人的运动范围
题目分析:[[EVD]] - 剑指 Offer 13. 机器人的运动范围https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-l ...
最新文章
- python3.9教程_Python3简明教程(九)—— 文件处理
- 一维二维_更高效的一维、二维材料过渡态搜索
- AC日记——[USACO10MAR]仓配置Barn Allocation 洛谷 P1937
- 推荐一款优雅的日历控件
- fck2.6.3配置
- SpringNote01.基于SpringMVC-Hibernate的Blog系统
- Hbase rowkey 设计原则
- 军用装备产品GJB150A淋雨试验检测机构
- 分析微信聊天记录(1)——获取微信聊天记录
- 最齐全的黑防VIP教程,个人认为不错(123课)
- vue3获取url后面参数
- 荣耀笔记本pro linux版本,荣耀MagicBook Pro锐龙版发布:首发锐龙7 3750H、还有Linux版...
- 远程桌面桌面无法找到计算机,Windows – 远程桌面客户端找不到远程计算机
- 买二手房不后悔先知道8件事 高楼层未必卖得好
- 结构化数据和半结构化数据和非结构化数据
- 总结八:面试程序员前需要的准备工作
- GDAL 遥感 图像处理 锐化(Laplace算子、Sobel算子)
- 学习OpenCV(1)概述
- HAproxy正向代理配置
- 经典仿句100例_仿写句子_二年级仿写句子100例