这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
题目
63. 不同路径 II
解析
其实跟之前的
- 不同路径
问题类似,只是这里增加了一个会挡路的设定:
-
网格中的障碍物和空位置分别用 1 和 0 来表示。
那么加上对应的校验,改造一下原来的代码,我们的代码应该也能AC的。
核心不变,加上对应校验后,我们的代码如下:
public static int uniquePathsWithObstacles(int[][] obstacleGrid) {
int[][] rec = new int[obstacleGrid.length][obstacleGrid[0].length];
return r(0,0,obstacleGrid,rec);
}
public static int r(int x,int y,final int[][] data,int[][] rec){
if(x<0 || x > data.length-1 || y<0 || y>data[0].length-1 || data[x][y] == 1) return 0;
if(x == data.length-1 && y == data[0].length-1) return 1;
if(rec[x][y]!=0) return rec[x][y];
rec[x][y] = r(x+1,y,data,rec) + r(x,y+1,data,rec);
return rec[x][y];
}
执行用时:
4 ms, 在所有 Java 提交中击败了12.85%的用户
内存消耗:
37.8 MB, 在所有 Java 提交中击败了30.32%的用户
此时我们发现了一个问题:
- 按照相同的题解,相对来说我们的成绩变差了
思考一下我们的dp数组:
- 既然我们只能从左上到右下,那么通到一个格子的最后一步,要么是从左边进入,要么是从上边进入。
那么我们的dp数组就可以变成一维的了,根据上面的思考结果可以得出,实际上:
- 走到(x,y)有多少种方法,其实就是走到(x-1,y)和(x,y-1)的方法的可能性相加。
那么根据这个结论,我们就可以很容易地改进我们的算法,改进点如下:
-
使用一维数组代替二维数组,降低空间复杂度
-
简单的逻辑验证:
- 我们使用一维数组,从左往右计算
- dp[j] = dp[j-1] + dp[j]
- 我们总会把前面的覆盖掉,这样子保证dp[j-1]代表的是这个位置的前一个数;等式右边的dp[j]代表的是上面的数。
-
-
使用循环代替递归(用类似BFS的方式每部结算,来代替DFS),减少方法栈帧的占用
代码如下:
int y = obstacleGrid.length,x = obstacleGrid[0].length;
//二维变一维
int[] dp = new int[x];
dp[0] = obstacleGrid[0][0] == 1? 0:1;
for (int i = 0; i < y; i++) {
for (int j = 0; j < x; j++) {
if(obstacleGrid[i][j] == 1){
dp[j] = 0;
continue;
}
dp[j] = (j-1<0?0:dp[j-1])+dp[j];
}
}
return dp[x-1];
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了29.08%的用户
采取相同的策略,我们也可以很轻松地完成64. 最小路径和。
\