问题描述
小R正在玩一个迷宫游戏。他的起始位置位于一个n行m列的矩形棋盘的左上角 (1,1),目标是移动到棋盘的右下角 (n,m)。棋盘上的每个格子要么是道路("0"),要么是障碍("1")。小R每次只能向右或向下移动,而且必须避开障碍。请你计算小R从 (1,1) 移动到 (n,m) 的所有可能路径数,并将结果对 10^9 + 7 取模。
测试样例
样例1:
输入:
n = 2, m = 3, maze = ["000", "100"]输出:2
样例2:
输入:
n = 5, m = 5, maze = ["00000", "10000", "10000", "00000", "00000"]输出:35
样例3:
输入:
n = 3, m = 3, maze = ["010", "010", "000"]输出:1
这个问题是一个典型的 动态规划 问题,目标是计算从起点 (1,1) 到终点 (n,m) 的所有可能路径数。由于每次只能向右或向下移动,而且必须避开障碍,我们可以通过动态规划来解决。
思路分析
虽然这个题的类别是图论的知识,但是这个问题可以通过 动态规划来求解。
需要从起点 (1,1) 移动到终点 (n,m),并且每次只能向右或向下移动。为了计算所有可能的路径数,定义一个状态表示当前位置的路径数,并通过状态转移来逐步求解。
-
题目分析 我们需要计算从起点 (1,1) 到终点 (n,m) 的所有有效路径数。 每次只能向右或向下移动,而且要避开障碍(表示为 "1")。
ok这就是写代码时一个要注意的点。
目标是计算从起点到终点的所有路径数,并对结果取模 10^9 + 7。
取模的知识还记得吧
-
动态规划的状态定义 状态定义: 设 dp[i][j] 表示从起点 (1,1) 到达位置 (i+1, j+1) 的路径数。
dp[i][j] 的值是从 (i,j) 位置的前一步移动过来的路径数之和。 起始条件:起点 (1,1) 处的路径数为 1,即 dp[0][0] = 1,表示从起点到起点只有一种方式,就是不动。
转移方程: 对于每个位置 (i,j),可以从上方 (i-1,j) 或者左方 (i,j-1) 移动过来:
如果当前位置 (i,j) 不是障碍(即 maze[i][j] == '0'),则: dp[i][j] = dp[i-1][j] + dp[i][j-1],表示从上方或者左方两种情况的路径数相加。 如果当前位置是障碍(即 maze[i][j] == '1'),则 dp[i][j] = 0,表示该位置无法到达。
-
边界条件 起点:dp[0][0] = 1,即从起点出发的路径数是 1,如果起点有障碍,直接返回 0,因为无法开始。 障碍物:如果当前位置是障碍,则 dp[i][j] = 0,表示无法到达该位置。
-
状态转移过程 遍历棋盘的每一个位置 (i, j),并根据以下规则更新 dp[i][j]: 如果 maze[i][j] == '1',表示该位置是障碍,dp[i][j] = 0。 否则,计算路径数: 如果上方有位置(即 i > 0),则可以从上方来:dp[i][j] += dp[i-1][j]。 如果左方有位置(即 j > 0),则可以从左方来:dp[i][j] += dp[i][j-1]。 对路径数 dp[i][j] 进行取模操作,防止溢出。
-
最终结果 最终结果是 dp[n-1][m-1],即从 (1,1) 到 (n,m) 的路径数。返回该值并对 10^9 + 7 取模。
-
特例处理 起点或终点是障碍:如果起点或者终点是障碍,显然无法走到终点,直接返回 0。
-
时间复杂度分析 我们需要遍历棋盘的每个位置并更新 dp 数组的值。每个位置的更新是常数时间操作。 因此,时间复杂度为 O(n * m),其中 n 是行数,m 是列数。
-
空间复杂度分析 我们使用了一个二维数组 dp 来保存每个位置的路径数,因此空间复杂度为 O(n * m)。
好了基本的思路就是这样,接下来就是编码阶段
有没有发现动态规划的题目有很多类似的地方