063.不同路径 II
作者:沉默王二
发布时间:2022-11-25T08:45:43.740+0800
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I
063.不同路径 II
题意
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 机器人)。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 星星 )。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
难度
中等
示例
示例1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
解释:3x3 网格的正中间有一个障碍物。从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下2. 向下 -> 向下 -> 向右 -> 向右
示例2:
输入:obstacleGrid = [[0,1],[0,0]]
分析
本题和 062.不同路径 是同一系列的题目,相较于 062.不同路径 什么限制都没有,这题在网格中添加了障碍物,这让我们不能直接利用数学规律得出答案,所以只能够老老实实地采取我们在 062.不同路径 使用的第一种方法——动态规划 。
还是用f[i][j]来表示走到第i行第j列的方案数,那么显然,如果一个格子被障碍物占领了,那么这个点就是无法抵达的——也就是当前位置的f[i][j] = 0,并且它的下方和右边也都无法从它这边穿过,我们没有办法从这个点再走到其他点。
所以我们就可以写出如下的动态转移方程
当i = 0或者j = 0时候,f[i][j]只可能有两种取值—— 0或1 ,这样子的情况下,只能有一种方案存在,也就是只能向一个方向走到底,但是如果这个方向上存在障碍物,就不能到达了,所以我们需要特殊处理。
class Solution {
int[][] f = new int[obstacleGrid.length][obstacleGrid[0].length]; for(int i = 0;i < obstacleGrid.length && obstacleGrid[i][0] == 0;i++) f[i][0] = 1; for(int j = 0;j < obstacleGrid[0].length && obstacleGrid[0][j] == 0;j++) f[0][j] = 1; for(int i = 1;i < obstacleGrid.length;i++){ for(int j = 1;j < obstacleGrid[0].length;j++){ if(obstacleGrid[i][j] == 1) { f[i][j] = 0; continue; } f[i][j] = f[i - 1][j] + f[i][j - 1]; } } return f[obstacleGrid.length - 1][obstacleGrid[0].length - 1]; }}
时间复杂度:
空间复杂度:
时间复杂度我们已经很难再加以改进了,但是这个空间复杂度以及这个转移方程,能不能优化一下呢?
当然可以—— 滚动数组!!!
实际上我们观察这个 动态转移方程 ,其实跟f[i][j]有关的只有f[i - 1][j]和f[i][j - 1],除此之外,别的都不能够直接影响它,所以我们可以考虑用一个一维数组来简化这个f[i][j],实现的细节可以看下面的代码。
class UniquePathsWithObstacles {
int[] f = new int[obstacleGrid[0].length]; f[0] = (obstacleGrid[0][0] == 0) ? 1 : 0;//特殊处理 for (int[] ints : obstacleGrid) { for (int j = 0; j < obstacleGrid[0].length; j++) { if (ints[j] == 1) { f[j] = 0; continue; } if (j >= 1 && ints[j - 1] == 0) f[j] += f[j - 1]; //滚动数组的精髓,因为一开始的f[i][j]是由f[i - 1][j]和f[i][j - 1]转移来的,化成一维之后,我们相当于直接对原本的f[i - 1][j]加上f[i][j - 1] } } return f[obstacleGrid[0].length - 1]; }}
这样一来,空间复杂度便降低到了
总结
滚动数组是动态规划中比较常见的优化方式,常常用于不需要存储子问题的答案的情况,也就是当前的f[i][j]仅仅直接跟常数个变量有关,并且这些变量都不会再次变化。
力扣链接:https://leetcode.cn/problems/unique-paths-ii/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1000 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I
063.不同路径 II
题意
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 机器人)。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 星星 )。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
难度
中等
示例
示例1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
解释:3x3 网格的正中间有一个障碍物。从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下2. 向下 -> 向下 -> 向右 -> 向右
示例2:
输入:obstacleGrid = [[0,1],[0,0]]
分析
本题和 062.不同路径 是同一系列的题目,相较于 062.不同路径 什么限制都没有,这题在网格中添加了障碍物,这让我们不能直接利用数学规律得出答案,所以只能够老老实实地采取我们在 062.不同路径 使用的第一种方法——动态规划 。
还是用f[i][j]来表示走到第i行第j列的方案数,那么显然,如果一个格子被障碍物占领了,那么这个点就是无法抵达的——也就是当前位置的f[i][j] = 0,并且它的下方和右边也都无法从它这边穿过,我们没有办法从这个点再走到其他点。
所以我们就可以写出如下的动态转移方程
当i = 0或者j = 0时候,f[i][j]只可能有两种取值—— 0或1 ,这样子的情况下,只能有一种方案存在,也就是只能向一个方向走到底,但是如果这个方向上存在障碍物,就不能到达了,所以我们需要特殊处理。
class Solution {
int[][] f = new int[obstacleGrid.length][obstacleGrid[0].length]; for(int i = 0;i < obstacleGrid.length && obstacleGrid[i][0] == 0;i++) f[i][0] = 1; for(int j = 0;j < obstacleGrid[0].length && obstacleGrid[0][j] == 0;j++) f[0][j] = 1; for(int i = 1;i < obstacleGrid.length;i++){ for(int j = 1;j < obstacleGrid[0].length;j++){ if(obstacleGrid[i][j] == 1) { f[i][j] = 0; continue; } f[i][j] = f[i - 1][j] + f[i][j - 1]; } } return f[obstacleGrid.length - 1][obstacleGrid[0].length - 1]; }}
时间复杂度:
空间复杂度:
时间复杂度我们已经很难再加以改进了,但是这个空间复杂度以及这个转移方程,能不能优化一下呢?
当然可以—— 滚动数组!!!
实际上我们观察这个 动态转移方程 ,其实跟f[i][j]有关的只有f[i - 1][j]和f[i][j - 1],除此之外,别的都不能够直接影响它,所以我们可以考虑用一个一维数组来简化这个f[i][j],实现的细节可以看下面的代码。
class UniquePathsWithObstacles {
int[] f = new int[obstacleGrid[0].length]; f[0] = (obstacleGrid[0][0] == 0) ? 1 : 0;//特殊处理 for (int[] ints : obstacleGrid) { for (int j = 0; j < obstacleGrid[0].length; j++) { if (ints[j] == 1) { f[j] = 0; continue; } if (j >= 1 && ints[j - 1] == 0) f[j] += f[j - 1]; //滚动数组的精髓,因为一开始的f[i][j]是由f[i - 1][j]和f[i][j - 1]转移来的,化成一维之后,我们相当于直接对原本的f[i - 1][j]加上f[i][j - 1] } } return f[obstacleGrid[0].length - 1]; }}
这样一来,空间复杂度便降低到了
总结
滚动数组是动态规划中比较常见的优化方式,常常用于不需要存储子问题的答案的情况,也就是当前的f[i][j]仅仅直接跟常数个变量有关,并且这些变量都不会再次变化。
力扣链接:https://leetcode.cn/problems/unique-paths-ii/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1000 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
本题解同时收录在星球专栏《二哥的 LeetCode 刷题笔记》中,专栏托管在语雀平台上(更方便你沉浸式阅读和做笔记,数学表达公式也能显示出来),访问地址和密码:https://t.zsxq.com/6iuzn6I
063.不同路径 II
题意
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 机器人)。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 星星 )。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
难度
中等
示例
示例1:
输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
解释:3x3 网格的正中间有一个障碍物。从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下2. 向下 -> 向下 -> 向右 -> 向右
示例2:
输入:obstacleGrid = [[0,1],[0,0]]
分析
本题和 062.不同路径 是同一系列的题目,相较于 062.不同路径 什么限制都没有,这题在网格中添加了障碍物,这让我们不能直接利用数学规律得出答案,所以只能够老老实实地采取我们在 062.不同路径 使用的第一种方法——动态规划 。
还是用f[i][j]来表示走到第i行第j列的方案数,那么显然,如果一个格子被障碍物占领了,那么这个点就是无法抵达的——也就是当前位置的f[i][j] = 0,并且它的下方和右边也都无法从它这边穿过,我们没有办法从这个点再走到其他点。
所以我们就可以写出如下的动态转移方程
当i = 0或者j = 0时候,f[i][j]只可能有两种取值—— 0或1 ,这样子的情况下,只能有一种方案存在,也就是只能向一个方向走到底,但是如果这个方向上存在障碍物,就不能到达了,所以我们需要特殊处理。
class Solution {
int[][] f = new int[obstacleGrid.length][obstacleGrid[0].length]; for(int i = 0;i < obstacleGrid.length && obstacleGrid[i][0] == 0;i++) f[i][0] = 1; for(int j = 0;j < obstacleGrid[0].length && obstacleGrid[0][j] == 0;j++) f[0][j] = 1; for(int i = 1;i < obstacleGrid.length;i++){ for(int j = 1;j < obstacleGrid[0].length;j++){ if(obstacleGrid[i][j] == 1) { f[i][j] = 0; continue; } f[i][j] = f[i - 1][j] + f[i][j - 1]; } } return f[obstacleGrid.length - 1][obstacleGrid[0].length - 1]; }}
时间复杂度:
空间复杂度:
时间复杂度我们已经很难再加以改进了,但是这个空间复杂度以及这个转移方程,能不能优化一下呢?
当然可以—— 滚动数组!!!
实际上我们观察这个 动态转移方程 ,其实跟f[i][j]有关的只有f[i - 1][j]和f[i][j - 1],除此之外,别的都不能够直接影响它,所以我们可以考虑用一个一维数组来简化这个f[i][j],实现的细节可以看下面的代码。
class UniquePathsWithObstacles {
int[] f = new int[obstacleGrid[0].length]; f[0] = (obstacleGrid[0][0] == 0) ? 1 : 0;//特殊处理 for (int[] ints : obstacleGrid) { for (int j = 0; j < obstacleGrid[0].length; j++) { if (ints[j] == 1) { f[j] = 0; continue; } if (j >= 1 && ints[j - 1] == 0) f[j] += f[j - 1]; //滚动数组的精髓,因为一开始的f[i][j]是由f[i - 1][j]和f[i][j - 1]转移来的,化成一维之后,我们相当于直接对原本的f[i - 1][j]加上f[i][j - 1] } } return f[obstacleGrid[0].length - 1]; }}
这样一来,空间复杂度便降低到了
总结
滚动数组是动态规划中比较常见的优化方式,常常用于不需要存储子问题的答案的情况,也就是当前的f[i][j]仅仅直接跟常数个变量有关,并且这些变量都不会再次变化。
力扣链接:https://leetcode.cn/problems/unique-paths-ii/
一步一个脚印
不积跬步无以至千里,不积小流无以成江海。LeetCode - 100天从算法小白到卷王正式启动了,我们计划周一到周五至少每天更新一篇,周六周日更新一篇,目标 300 道 LeetCode 经典题。
PDF 版本目前只针对**二哥编程星球 的球友开放,如果你也想一起打卡学习算法的话,戳链接 **加入我们吧。
一个人可以走得很快,但一群人才能走得更远。二哥编程星球 (目前已有 1000 多名球友加入)里面的每个球友都非常的友善,除了鼓励你,还会给你提出合理的建议,一起冲!
知识星球
扫码加入星球
查看更多优质内容
https://wx.zsxq.com/mweb/views/joingroup/join_group.html?group_id=15522885221412