剑指 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。请问该机器人能够到达多少个格子?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

输入:m = 2, n = 3, k = 1
输出:3

二、使用步骤

1.1 深度优先—递归

1.1.1 解决思路

  1. 当前问题
    判断从(i,j) 出发,到(m-1,n-1)可以经过多少不重复的格子
  2. 划分为子问题
    (i+1,j)-------> (m-1,n-1)
    (i-1,j)-------> (m-1,n-1)
    (i,j+1)-------> (m-1,n-1)
    (i,j-1)-------> (m-1,n-1)
    即,从(i,j)开始为4个子问题相加+1(当前 i,j 格子)
  3. 判断终止条件及剪枝
    ① i,j越界
    ② 不重复的格子
    设置 v i s t e d [ i ] [ j ] = T r u e / F a l s e visted[i][j]=True/False visted[i][j]=True/False , 判断其是否已经被访问过
    ③ 数位和 > k

1.1.2 具体代码

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        #回溯法
        def digitalSum(s):
            res=0
            while s:
                res+=s%10
                s=s//10
            return res

  
        def backstacking(i,j,k):
            if i<0 or i>=m or j<0 or j>=n:
                return 0
            #如果行列坐标位数之后大于k,不能进入
            if visted[i][j]:
                return 0
           
            if digitalSum(i)+digitalSum(j)>k:
                return 0

            visted[i][j]=True
            res=1+backstacking(i-1,j,k)+backstacking(i+1,j,k)+backstacking(i,j+1,k)+backstacking(i,j-1,k)
            return res
       
        visted=[[0 for i in range(n)] for j in range(m)]
        return(backstacking(0,0,k))

时间复杂度:最坏情况下,需要访问整个(m-1,n-1). O(mn)
空间复杂度:维护了一个visted[][], O(mn)

1.1.3 改进

  1. 使用set()动态维护已经访问过的元素,节省空间
			 set1=set()
			 
             set1.add((i,j))
             
             if (i,j) in set1:
                return 0
  1. 从点(0,0)出发,仅向下向右就可以遍历所有解。
    在这里插入图片描述
  2. 使用si,sj表示i,j数位和
    当(i+1)%10==0时,s(i+1)=s(i)-8
    i=9,i+1=10-----> si=9,s(i+1)=1,------>s(i+1)=s(i)-8
    当(i+1)%10!=0时,s(i+1)=s(i)+1
    i=8,i+1=9-----> si=8,s(i+1)=9,------>s(i+1)=s(i)+1
    三元运算符表示为:
si+1 if (i+1)%10 else si-8
class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        #回溯法
        # def digitalSum(s):
        #     res=0
        #     while s:
        #         res+=s%10
        #         s=s//10
        #     return res

        def backstacking(i,j,k,si,sj):
            if i<0 or i>=m or j<0 or j>=n:
                return 0
          
            # if visted[i][j]:
            #     return 0
            if (i,j) in set1:
                return 0
            
             #如果行列坐标位数之后大于k,不能进入
            # if digitalSum(i)+digitalSum(j)>k:
            #     return 0
            if si+sj>k:
                return 0 

            #visted[i][j]=True
            set1.add((i,j))
            #仅向下向右就可以遍历所有解

            res=1+backstacking(i+1,j,k,si+1 if (i+1)%10 else si-8,sj)+backstacking(i,j+1,k,si,sj+1 if (j+1)%10 else sj-8)
            return res
       
        #visted=[[0 for i in range(n)] for j in range(m)]
        set1=set()
        return(backstacking(0,0,k,0,0))
class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:

        def backstacking(i,j,k,si,sj):
            if i<0 or i>=m or j<0 or j>=n:
                return 0
            
            if (i,j) in set1:
                return 0
            
            if si+sj>k:
                return 0 

            set1.add((i,j))

            #仅向下向右就可以遍历所有解
            res=1+backstacking(i+1,j,k,si+1 if (i+1)%10 else si-8,sj)+backstacking(i,j+1,k,si,sj+1 if (j+1)%10 else sj-8)
            return res
       
        set1=set()
        return(backstacking(0,0,k,0,0))

Krahets
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/

2.广度优先–队列

class Solution:
    
    def movingCount(self, m: int, n: int, k: int) -> int:
        def digitalSum(s):
            res=0
            while s:
                res+=s%10
                s=s//10
            return res

        q=collections.deque()
        q.append((0,0))
        s=set()

        while q:
            i,j=q.popleft()
           
            if i>=0 and i<m and j>=0 and j<n and (i,j) not in s and digitalSum(i)+digitalSum(j)<=k:
                s.add((i,j))
                for l,r in [(i+1,j),[i,j+1]]:
                    q.append((l,r))
                   
        return len(s)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值