• python每日一题【剑指 Offer 13. 机器人的运动范围】


    day23-2022.11.18

    题目信息来源
    作者:Krahets
    链接:https://leetcode.cn/leetbook/read/illustration-of-algorithm
    来源:力扣(LeetCode)

    剑指 Offer 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
    • 2
    • 3
    • 4
    • 5

    提示:

    • 1 <= n,m <= 100

    • 0 <= k <= 20

    题解:个人版

    昨天做了一题,总之能照猫画虎做出来一题

    • 递归参数:行坐标i, 列坐标j

    • 终止条件:超出边界,不符合规则,已经看过的地方。用了一个二维列表来标记,还踩了雷。

    • 递推工作:标记已经选过的列表,搜索下一个单元格,计数

    • 返回值:无。选择了一个全局变量来计数,说实话,我没太想好怎么在递归中计数,这个尝试失败了

    相关知识点

    行坐标和列坐标的数位之和计算,设行坐标为i,列坐标为j,则计算行坐标数位之和为i//10+i%10,即整除和取余。我这里可能钻了测试题的漏洞,如果出现m,n=100,可能就bug了。

    class Solution:
        def movingCount(self, m: int, n: int, k: int) -> int:
            # 递归参数:行坐标i, 列坐标j
            # 终止条件:超出边界,不符合规则
            # 递推工作:标记已经选过的列表,搜索下一个单元格,计数
            # 返回值
            self.m, self.n, self.k = m, n, k
            self.result = 0
            self.myset = [[0 for x in range(n)] for x in range(m)]
            self.move(0, 0)
            return self.result
    
        def move(self, i, j):
            if i>=self.m or j>=self.n:return
        	#if i<0 or i>=self.m or j<0 or j>=self.n:return
            if self.myset[i][j]==1:return
            if self.myset[i][j]==0:
                self.myset[i][j] = 1
                if (i//10+i%10+j//10+j%10)>self.k:return
                else:self.result = self.result + 1
            # self.move(i-1, j)
            self.move(i+1, j)
            # self.move(i, j-1)
            self.move(i, j+1)
            return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    题解:官方

    官方题解知识点重点

    1. 数位增量和公式解释:若xx+1不超过两位数
    • x + 1 / / 10 = 0 x+1//10=0 x+1//10=0 时, x x x 的个位为9, x + 1 x+1 x+1 的个位为0,比 x x x 小9, x + 1 x+1 x+1 的十位比 x x x 的十位大1,整体就比 x x x 小8
    • x + 1 / / 10 ≠ 0 x+1//10\neq0 x+1//10=0 时,就比 x x x 大1
    1. 理解不可达解:有限制,机器人每次只能走一步。只有之前走过的连通了才可以。
    2. 剪枝:分析可知机器人可通过只往增序列处走就能访问所有可达解。(然后我偷偷注释了我代码里递归的两行,试了一下,确实不影响结果并且提升了速度减少了内存)
    3. 我也尝试用set()来标记走过的点,来剪枝,但是失败了,因为我的语法是set.add([i,j]),看了解析用的是set.add((i,j))
    4. 关于我没法把计数放到递归里的解决方案:解析里用的是+,如果不符合条件的直接会返回 0,所以会没有变化,其他情况都是被1+

    but,官方解析里sisj的写法很容易混淆,其实就是 x 和 x+1 的数位之和

    广度优先遍历 BFS

    以平推的方式向前搜索,通常会利用队列实现。

    • 初始化:将初始点加入队列
    • 迭代终止条件:队列为空
    • 迭代工作:
      • 出队
      • 判断是否跳过
      • 标记
      • 入队

    尝试复现官方题解的广度优先遍历

    class Solution:
        def movingCount(self, m: int, n: int, k: int) -> int:
            # 初始化需要队列遍历存储遍历的列表,需要一个列表存储已经标记过的格子
            myqueue = [(0, 0, 0, 0)]
            choosed = set()
            while myqueue:
                x, y, sum_x, sum_y = myqueue.pop(0)
                if x>=m or y>=n or sum_x+sum_y>k or (x,y) in choosed:continue
                choosed.add((x, y))
                myqueue.append((x+1, y, sum_x+1 if (x+1)%10!=0 else sum_x-8, sum_y))
                myqueue.append((x, y+1, sum_x, sum_y+1 if (y+1)%10!=0 else sum_y-8))
            return len(choosed)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Java8 Stream生成流 generate iterate IntStream
    使用IVX来创造一个自己的3D小游戏【后台和中台、React Core、three.js、Pixi.js、Krpano、antD......】
    lvgl不能显示图片,但可以显示按键?
    【1】Docker安装
    仿大众点评——秒杀系统部分02
    Jmeter对图片验证码的处理
    第十三届蓝桥杯省赛C++B组题解
    Latex内容超出页面 行 的长度
    【JVM 系列】JVM 对象的分配策略
    webgoat-(A1)SQL Injection
  • 原文地址:https://blog.csdn.net/qq_42896431/article/details/128104496