【leetcode】 - 不同路径Ⅱ

212 阅读2分钟

这是我参与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. 最小路径和

\