题目与题解
62.不同路径
题目链接:62.不同路径
代码随想录题解:62.不同路径
解题思路:
经典dp路径题,按五部曲走:
dp数组下标及含义:i,j表示当前坐标,dp[i][j]表示走到(i,j)时一共有多少不同路径
确定递推公式:由于只能向右或向下走,那么要走到当前坐标,必然是从当前坐标的上面或左边走过来的,所以路径总数就是走到上面坐标的路径数加上走到左边坐标的路径数,一共有dp[i][j] = dp[i-1][j] + dp[i][j-1]个
数组初始化:递推公式中有i-1,j-1,所以所有下标存在0的点都必须初始化,否则dp[-1]这种坐标不存在无法计算,因此第一行和第一列都初始化,且有且只有一条路径,初始化值为1。
确定遍历顺序:因为目标是向右或向下走,所以要保证它左边和上面的dp都有值,逐行遍历即可。
举例说明:随便选一个题目给的example试试就行,如[3,7]
class Solution {
public int uniquePaths(int m, int n) {
int[][] paths = new int[m][n];
for (int i = 0; i < m; i++) {
paths[i][0] = 1;
}
for (int i = 0; i < n; i++) {
paths[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
paths[i][j] = paths[i-1][j] + paths[i][j-1];
}
}
return paths[m-1][n-1];
}
}
看完代码随想录之后的想法
dp做法比较常规,数论的方法很有意思,相当于不是用代码递推,而是直接获取数学公式求解。做阶乘的时候要谨防溢出,有点难,学习一下。
class Solution {
public:
int uniquePaths(int m, int n) {
long long numerator = 1; // 分子
int denominator = m - 1; // 分母
int count = m - 1;
int t = m + n - 2;
while (count--) {
numerator *= (t--);
while (denominator != 0 && numerator % denominator == 0) {
numerator /= denominator;
denominator--;
}
}
return numerator;
}
};
遇到的困难
初始化时一开始只想着初始化0,1和1,0处的路径就好,但是我下面遍历求解时还是从i=1和j=1开始的,所以算出来就不对了。有时候还是得举例说明,看看有没有出错。
63. 不同路径 II
题目链接:63. 不同路径 II
代码随想录题解:63. 不同路径 II
解题思路:
基础思路跟上一题是一样的,不同地方在于多了对障碍物的处理。
dp数组下标及含义:i,j表示当前坐标,dp[i][j]表示走到(i,j)时一共有多少不同路径
确定递推公式:由于只能向右或向下走,那么要走到当前坐标,必然是从当前坐标的上面或左边走过来的,所以路径总数就是走到上面坐标的路径数加上走到左边坐标的路径数,一共有dp[i][j] = dp[i-1][j] + dp[i][j-1]个,但是如果当前点就有障碍,该点无法到达,dp[i][j]=0
数组初始化:第一行和第一列都初始化,且有且只有一条路径,初始化值为1,如果碰到障碍,后面的点都不可达,初始化为0。
确定遍历顺序:因为目标是向右或向下走,所以要保证它左边和上面的dp都有值,逐行遍历即可。
举例说明:随便选一个题目给的example试试就行,如[[0,0,0],[0,1,0],[0,0,0]]
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int[][] path = new int[obstacleGrid.length][obstacleGrid[0].length];
for (int i = 0; i < path.length; i++) {
if (obstacleGrid[i][0] == 1) {
break;
} else {
path[i][0] = 1;
}
}
for (int j = 0; j < path[0].length; j++) {
if (obstacleGrid[0][j] == 1) {
break;
} else {
path[0][j] = 1;
}
}
int m = path.length, n = path[0].length;
for (int i = 1; i < path.length; i++) {
for (int j = 1; j < path[0].length; j++) {
if (obstacleGrid[i][j] == 1) {
path[i][j] = 0;
} else {
path[i][j] = path[i-1][j] + path[i][j-1];
}
}
}
return path[m-1][n-1];
}
}
看完代码随想录之后的想法
写法上会更优化一点,比如初始化的时候不用进了循环再判断是否break,可以直接把条件写在循环条件里。
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
基础思路还是很清晰的。
遇到的困难
一开始想错了一个地方,把不可达的点的dp设置为-1了,跟自己一开始的定义其实矛盾了,导致后面计算的时候多写了很多的判断条件,而且这里有两个数组,写条件的时候一开始也写混了,导致各种小错误堆积出了很多怪错误。细心细心!
今日收获
加深了一下对dp的理解,这两道题也算是经典题了,比较简单。