一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1
和 0
来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入: [ [0,0,0], [0,1,0], [0,0,0] ] 输出: 2 解释: 3x3 网格的正中间有一个障碍物。 从左上角到右下角一共有2
条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 -> 向右
1 #include "_000库函数.h" 2 3 4 //还是用动态规划Dynamic Programming来解,我们使用一个二维的dp数组,大小为(m + 1) x(n + 1), 5 //这里的dp[i][j] 表示到达(i - 1, j - 1) 位置的不同路径的数量, 6 //那么i和j需要更新的范围就是[1, m] 和[1, n]。状态转移方程跟之前那道题是一样的, 7 //因为每个位置只能由其上面和左面的位置移动而来, 8 //所以也是由其上面和左边的dp值相加来更新当前的dp值,即: 9 // 10 //dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 11 // 12 //这里就能看出来我们初始化dp数组的大小为(m + 1) x(n + 1), 13 //是为了handle边缘情况,当i或j为0时,减1可能会出错。 14 //当某个位置是障碍物时,其dp值为0,我们直接跳过该位置即可。 15 //我们还需要初始化dp数组的某个值,使得其能正常累加。当起点不是障碍物时, 16 //其dp值应该为值,即dp[1][1] = 1,由于其是由 dp[0][1] + dp[1][0] 更新而来, 17 //所以二者中任意一个初始化为1即可。由于之后LeetCode更新了这道题的test case, 18 //使得使用int型的dp数组会有溢出的错误,所以我们改为使用long型的数组来避免overflow,代码如下: 19 20 class Solution { 21 public: 22 int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) { 23 if (obstacleGrid.empty() || obstacleGrid[0].empty() || obstacleGrid[0][0] == 1) return 0; 24 int m = obstacleGrid.size(), n = obstacleGrid[0].size(); 25 vector<vector<long>> dp(m + 1, vector<long>(n + 1, 0)); 26 dp[0][1] = 1; 27 for (int i = 1; i <= m; ++i) { 28 for (int j = 1; j <= n; ++j) { 29 if (obstacleGrid[i - 1][j - 1] != 0) continue; 30 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 31 } 32 } 33 return dp[m][n]; 34 } 35 }; 36 37 void T063() { 38 Solution s; 39 vector<vector<int>>v; 40 v = { {0, 0, 0}, 41 {0, 1, 0}, 42 {0, 0, 0} }; 43 cout << s.uniquePathsWithObstacles(v) << endl; 44 }