❇️Day 39 第九章 动态规划 part02
✴️今日任务
今天开始逐渐有 dp的感觉了,题目不多,就两个 不同路径,可以好好研究一下
- 62.不同路径
- 63.不同路径 II
❇️62.不同路径
- 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流,很难想到。
- 题目链接:https://leetcode.cn/problems/unique-paths/
- 视频讲解:https://www.bilibili.com/video/BV1ve4y1x7Eu
- 文章链接:https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html
自己的思路
- dp数组及下标的含义
定义一个二维数组dp[i][j]表示机器人到第i行第j列的格有dp[i][j]种路径
i的最大值为m,j的最大值为n
int dp[][] = new int[m + 1][n + 1]; - 递归函数
当前格可以通过上面一格往下或左面一格往右
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; - dp数组初始化
dp[0][], dp[][0]相当于在网格上面和左边分别多增加一行一列
dp[1][1] = 1; dp[0][] = 0; dp[][0] = 0; - 遍历顺序
先从上到下再从左到右
dp[1][1]->dp[2][1]->···->dp[m][1]->dp[1][2]->dp[2][2]->···
或从左到右在从上到下
dp[1][1]->dp[1][2]->···->dp[1][n]->dp[2][1]->dp[2][2]->··· - 打印dp数组
自己的代码
class Solution {
public int uniquePaths(int m, int n) {
int dp[][] = new int[m + 1][n + 1];
dp[1][1] = 1;
for (int i = 0; i <= m; i++) {
dp[i][0] = 0;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = 0;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if(i == 1 && j == 1) continue;
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
//System.out.println(Arrays.toString(dp[i]));
}
return dp[m][n];
}
}
随想录思路
- dp数组及下标的含义
定义一个二维数组dp[i][j]表示机器人到第i行第j列的格有dp[i][j]种路径
i的最大值为m - 1,j的最大值为n - 1
int dp[][] = new int[m][n]; - 递归函数
- dp数组初始化
dp[0][], dp[][0]都初始化为1 - 遍历顺序
- 打印dp数组
随想录代码
/**
* 1. 确定dp数组下标含义 dp[i][j] 到每一个坐标可能的路径种类
* 2. 递推公式 dp[i][j] = dp[i-1][j] dp[i][j-1]
* 3. 初始化 dp[i][0]=1 dp[0][i]=1 初始化横竖就可
* 4. 遍历顺序 一行一行遍历
* 5. 推导结果 。。。。。。。。
*
* @param m
* @param n
* @return
*/
public static int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
//初始化
for (int i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (int i = 0; i < n; i++) {
dp[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
❇️63. 不同路径 II
- 题目链接:https://leetcode.cn/problems/unique-paths-ii/
- 视频讲解:https://www.bilibili.com/video/BV1Ld4y1k7c6
- 文章链接:https://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.html
自己的思路
- dp数组及下标的含义
定义一个二维数组dp[i][j]表示机器人到第i行第j列的格有dp[i][j]种路径
i的最大值为m - 1,j的最大值为n - 1
int dp[][] = new int[m][n]; - 递归函数
当前格可以通过上面一格往下或左面一格往右
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; - dp数组初始化
当obstacleGrid[0][]和obstacleGrid[][0]不为1时对应的dp[0][]和dp[][0]为1,否则为0
❗当前面或上面有障碍那后面都得初始化为0 - 遍历顺序
先从左到右再从上到下 - 打印dp数组
自己的代码
踩坑:
初始化错误
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int dp[][] = new int[obstacleGrid.length][obstacleGrid[0].length];
//初始化
for (int i = 0; i < dp.length; i++) {
if(obstacleGrid[i][0] == 0){
dp[i][0] = 1;
}else{
for (int j = i; j < dp.length; j++) {
dp[j][0] = 0;
}
break;
}
}
for (int j = 0; j < dp[0].length; j++) {
if(obstacleGrid[0][j] == 0){
dp[0][j] = 1;
}else{
for (int i = j; i < dp[0].length; i++) {
dp[0][i] = 0;
}
break;
}
}
// for (int i = 0; i < dp.length; i++) {
// System.out.println("*"+Arrays.toString(dp[i]));
// }
// System.out.println(Arrays.toString(dp[0]));
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if(obstacleGrid[i][j] == 0){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}else{
dp[i][j] = 0;
}
}
//System.out.println(Arrays.toString(dp[i]));
}
return dp[dp.length - 1][dp[0].length - 1];
}
}
随想录代码
遇到障碍之后可以不初始化,没赋值默认为0
起始有障碍or终止有障碍直接返回0
可以在for循环中间添加条件
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
//如果在起点或终点出现了障碍,直接返回0
if (obstacleGrid[m - 1][n - 1] == 1 || obstacleGrid[0][0] == 1) {
return 0;
}
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) {
dp[i][0] = 1;
}
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) {
dp[0][j] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = (obstacleGrid[i][j] == 0) ? dp[i - 1][j] + dp[i][j - 1] : 0;
}
}
return dp[m - 1][n - 1];
}
}