LeetCode笔记-机器人的运动范围( Python图解)

个人微信公众号:AI研习图书馆,欢迎关注~

深度学习知识及资源分享,学习交流,共同进步~

一、题目描述

面试题13:机器人的运动范围
难度:中等

地上有一个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

二、解题实现

1. 解题思路

本题与 矩阵中的路径 类似,是典型的矩阵搜索问题。此类问题通常可使用 深度优先搜索(DFS) 或 广度优先搜索(BFS) 解决。在介绍 DFS / BFS 算法之前,为提升计算效率,首先讲述两项前置工作: 数位之和计算 、搜索方向简化 。

数位之和计算:
在这里插入图片描述

def sums(x):
    s = 0
    while x:
        s += x % 10
        x = x // 10
    return s

在这里插入图片描述

以下代码为增量公式的三元表达式写法,将整合入最终代码中。

s_x + 1 if (x + 1) % 10 else s_x - 8

搜索方向简化:

  • 数位和特点: 根据数位和增量公式得知,数位和每逢 进位 突变一次。

  • 解的三角形结构:

  • 根据数位和特点,矩阵中 满足数位和的解 构成的几何形状形如多个 等腰直角三角形 ,每个三角形的直角顶点位于 0, 10, 20, …0,10,20,… 等数位和突变的矩阵索引处 。

  • 三角形内的解虽然都满足数位和要求,但由于机器人每步只能走一个单元格,而三角形间不一定是连通的,因此机器人不一定能到达,称之为 不可达解 ;同理,可到达的解称为 可达解 (本题求此解) 。

  • 结论: 根据可达解的结构,易推出机器人可 仅通过向右和向下移动,访问所有可达解 。

  • 三角形内部: 全部连通,易证;

  • 两三角形连通处: 若某三角形内的解为可达解,则必与其左边或上边的三角形连通(即相交),即机器人必可从左边或上边走进此三角形。

图例展示了 n,m = 20 ,k∈[6,19] 的可达解、不可达解、非解,以及连通性的变化。

在这里插入图片描述
动态动画请参看以下链接:
动态演示

2. Python实现

2.1 方法一:深度优先遍历 DFS

在这里插入图片描述
在这里插入图片描述
深度优先搜索一般使用栈来实现。本题使用递归可以更轻松实现,我们定义一个递归函数 dfs(),如果坐标不满足条件,结束递归状态,否则将下一步满足条件的坐标代入递归函数。

在这里插入图片描述
python代码实现:

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        def sumofDigit(x, y):
            result = 0
            while x > 0:
                result += x % 10
                x //= 10
            while y > 0:
                result += y % 10
                y //= 10
            return result
        
        def dfs(i, j):
            if i == m or j == n or sumofDigit(i, j) > k or (i, j) in marked:
                return 
            marked.add((i, j))
            dfs(i + 1, j)
            dfs(i, j + 1)
            
        marked = set()
        dfs(0, 0)
        return len(marked)

复杂度分析:

  • 时间复杂度:O(m×n)。
  • 空间复杂度:O(m×n)。

2.2 方法二:广度优先搜索 BFS

广度优先搜索一般使用队列来实现。我们先将 (0, 0)加入队列,当队列不为空时,每次将队首坐标出队,加入到集合中,再将满足以上两个条件的坐标加入到队尾,直到队列为空。

在这里插入图片描述
Python代码实现:

在广度优先算法,由于可行解的连通性和结构,仅考虑向下和向右的移动方向即可,深度优先算法同样如此。

由于题目要求从 (0, 0) 点出发,因此任何一个点都可以只通过向右和向下两个动作达到,因此代码中可以只考虑这两个方向。

class Solution:
    def sum_rc(self,row,col):
        tmp = 0
        while row > 0:
            tmp += row % 10
            row //= 10
        while col > 0:
            tmp += col % 10
            col //= 10
        return tmp

    def movingCount(self, m: int, n: int, k: int) -> int:
        marked = set()  # 将访问过的点添加到集合marked中,从(0,0)开始
        queue = collections.deque()
        queue.append((0,0))
        while queue:
            x, y = queue.popleft()
            if (x,y) not in marked and self.sum_rc(x,y) <= k:
                marked.add((x,y)) 
                for dx, dy in [(1,0),(0,1)]:  # 仅考虑向右和向下即可
                    if 0 <= x + dx < m and 0 <= y + dy < n:
                        queue.append((x+dx,y+dy)) 
        return len(marked)     

复杂度分析:

  • 时间复杂度:O(m\times n)O(m×n)
  • 空间复杂度:O(m\times n)O(m×n)

码字不易,欢迎大家点赞,关注,精彩不断~

您的支持,是我不断创作的最大动力~

欢迎点赞关注留言交流~

深度学习,乐此不疲~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI研习图书馆

您的鼓励将是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值