63. 不同路径 II
题目:
思路:
【1】动态规划的方式
【2】递归的方式(深度搜索)
代码展示:
动态规划的方式:
【1】标准的耗费空间为M*N的方式:
//时间0 ms击败100% //内存39.5 MB击败77.63% //时间复杂度:O(M * N) //空间复杂度:O(M * N) //标准动态规划的方式 class Solution { public int uniquePathsWithObstacles(int[][] obstacleGrid) { int m = obstacleGrid.length; int n = obstacleGrid[0].length; int[][] dp = new int[m][n]; //这两个循环需要理解一下:由于只能向下和向右走 //所以第一行和第一列的值本质都是源于下标【0,0】的位置 //而且只有一种走法 for (int i = 0; i < m && obstacleGrid[i][0] != 1; i++) dp[i][0] = 1; for (int j = 0; j < n && obstacleGrid[0][j] != 1; j++) dp[0][j] = 1; for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { // 如果该位置放的是障碍物,那么就跳过 if (obstacleGrid[i][j] == 1) continue; // 否则能走到该位置就是从上方或者左方走到的 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } // 输出目标位置的路径数 return dp[m - 1][n - 1]; } }
【2】只使用一维数组的空间优化方式:
//对空间复杂度进行优化 //时间0 ms击败100% //内存39.2 MB击败97.31% //时间复杂度:O(nm),其中 n 为网格的行数,m 为网格的列数。我们只需要遍历所有网格一次即可。 //空间复杂度:O(m)。利用滚动数组优化,我们可以只用 O(m) 大小的空间来记录当前行的 f 值。 class Solution { public int uniquePathsWithObstacles(int[][] obstacleGrid) { int n = obstacleGrid.length, m = obstacleGrid[0].length; int[] f = new int[m]; // 因为一开始的位置如果不是被障碍物占据的话是要置为1 f[0] = obstacleGrid[0][0] == 0 ? 1 : 0; // 假设示例数据为 obstacleGrid = [[0,0,0],[0,0,0],[0,0,0]] for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (obstacleGrid[i][j] == 1) { f[j] = 0; continue; } // 为什么这样可以呢? // 原因是你直接往下走的话路径数是不会变的 // 所以如果你第一层为 [1, 1, 1] ,只按往下走的话,第二层必然也是[1, 1, 1] // 那么对于每个位置还要补的就是从左往右走 即 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; // 由于往下走这一步已经将 dp[i][j] = dp[i - 1][j] ; 所以 dp[i][j] 还要加上 dp[i][j - 1]; // 故就是 f[j] += f[j - 1]; if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) { f[j] += f[j - 1]; } } } return f[m - 1]; } }