提示:努力生活,开心、快乐的一天
62. 不同路径
💡解题思路
- 动规五部曲:
- 确定dp数组以及下标的含义:dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。
- 确定递推公式:想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1],dp[i - 1][j] 是从(0, 0)的位置到(i - 1, j)有几条路径,dp[i][j - 1]同理,那么,dp[i][j] = dp[i - 1][j] + dp[i][j - 1],因为dp[i][j]只有这两个方向过来。
- dp数组如何初始化:首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理。
- 确定遍历顺序:从上到下、从左到右遍历
- 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来## 🤔遇到的问题
- 初始化dp[i][0]和dp[0][j],需要提前进行,不能在遍历递推公式的时候同步进行初始化
💻代码实现
动态规划
var uniquePaths = function(m, n){
//定义一个二维数组
//dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。
let dp = Array(m).fill().map(item=>Array(n))
//首先dp[i][0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0][j]也同理。
for(let i=0; i<m; i++) dp[i][0] = 1
for(let i=0; i<n; i++) dp[0][i] = 1
//遍历顺序:从左到右;从上到下
for(let i=1; i<m; i++){
for(let j=1; j<n; j++){
//想要求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]。
dp[i][j] = dp[i-1][j]+dp[i][j-1]
}
}
console.log(dp)
return dp[m-1][n-1]
};
🎯题目总结
动规五部曲:
- 确定dp数组下标含义 dp[i][j] 到每一个坐标可能的路径种类
- 递推公式 dp[i][j] = dp[i-1][j] dp[i][j-1]
- 初始化 dp[i][0]=1 dp[0][i]=1 初始化横竖就可
- 遍历顺序 一行一行遍历
- 推导结果 。。。。。。。。
63. 不同路径 II
💡解题思路
- 与上一题基本一致,不同点如下
- 递推公式:需要注意一点,因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)
- dp数组初始化时,如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i][0]应该还是初始值0。
🤔遇到的问题
- 初始化的部分,很容易忽略了障碍之后应该都是0的情况
💻代码实现
动态规划
var uniquePathsWithObstacles = function(obstacleGrid) {
let m = obstacleGrid.length
let n = obstacleGrid[0].length
let dp = Array(m).fill().map(item=>Array(n).fill(0))
//一旦遇到obstacleGrid[i][0] == 1的情况就停止dp[i][0]的赋值1的操作,dp[0][j]同理
for(let i = 0; i < m&&obstacleGrid[i][0]===0; i++) dp[i][0] = 1
for(let i = 0; i < n&&obstacleGrid[0][i]===0; i++) dp[0][i] = 1
for(let i = 1; i < m; i++){
for(let j = 1; j <n;j++){
// 当(i, j)没有障碍的时候,再推导dp[i][j]
dp[i][j] = obstacleGrid[i][j]===1?0:dp[i-1][j]+dp[i][j-1]
}
}
console.log(dp)
return dp[m-1][n-1]
};
🎯题目总结
本题是62.不同路径 (opens new window)的障碍版,整体思路大体一致。
但就算是做过62.不同路径,在做本题也会有感觉遇到障碍无从下手。
其实只要考虑到,遇到障碍dp[i][j]保持0就可以了。
也有一些小细节,例如:初始化的部分,很容易忽略了障碍之后应该都是0的情况。
🎈今日心得
不同路径问题及有障碍的不同路径问题,学会啦