leetcode576.出界的路径数

出界的路径数

题目:给定一个 m × n 的网格和一个球。球的起始坐标为 (i,j) ,你可以将球移到相邻的单元格内,或者往上、下、左、右四个方向上移动使球穿过网格边界。但是,你最多可以移动 N 次。找出可以将球移出边界的路径数量。答案可能非常大,返回 结果 mod 10^9 + 7 的值。

方法一

一开始看题,以为类似机器人路径问题,直接用dfs迭代N次,从起点开始,将可到达的位置入栈,判断当前位置是否出界,若出界,路径数量加一;反之,将它下一步可到达的位置入栈。

但是本题与以往类似(做过)的题目有些不同,本题的路径是带返回的,也就是说,某个点可以重复多次被访问。这样下来,重复计算的量就很庞大。(其实从题目中返回结果mod 10 ^ 9 + 7就看出来,计算量不小哇。)

方法二

由于方法一超时,必须想到一种带记忆的算法解决本题有大量重复计算的特点。那么,动态规划它来啦!
因为球的每一次移动都是由上一次移动的结果决定的通过累加每一次移动后,球处于边界位置的状态数(当球处于边界位置的时候,下次一移动一定可以出界)并且乘以该边界位置可从几个方向出界(cnt<=3)。这样可以得到最终的球出界的路径数。

其中,动态转移方程为:
dp[i][j][k] = dp[i-1][j][k-1] + dp[i+1][j][k-1] + dp[i][j-1][k-1] + dp[i][j+1][k-1] ,k为移动次数。

这里初始化问题,为了简便,省去讨论边界问题,初始化的矩阵要大给定矩阵一圈。这样,在更新每个节点的值的时候,不用判断当前横、纵坐标是否越界。

class Solution(object):
    def findPaths(self, m, n, N, i, j):
        """
        :type m: int
        :type n: int
        :type N: int
        :type i: int
        :type j: int
        :rtype: int
        """
        lis = [[[0 for p in range(n+2)] for q in range(m+2)]]
        lis[0][i+1][j+1] = 1 #初始化,第0次移动起始节点值为1
        ans = 0              #路径个数
        k = 0                #移动次数
        while k < N:
            temp = [[0 for x in range(n+2)] for y in range(m+2)]
            for p in range(1,m+1):
                for q in range(1,n+1):
                    if lis[k][p][q] > 0: 
                        cnt = 0   #计算可出界的方向数
                        if p == 1:
                            cnt += 1
                        if p == m:
                            cnt += 1
                        if q == 1:
                            cnt += 1
                        if q == n:
                            cnt += 1
                        ans += cnt * lis[k][p][q] 
                    temp[p][q] = lis[k][p-1][q] + lis[k][p+1][q] + lis[k][p][q-1] + lis[k][p][q+1]        
            lis.append(temp)
            k += 1
        return ans % (10 ** 9 + 7)
发布了2 篇原创文章 · 获赞 2 · 访问量 60

猜你喜欢

转载自blog.csdn.net/weixin_38022038/article/details/104797607