一、62.不同路径
题目链接:https://leetcode.cn/problems/unique-paths/
文章讲解:https://programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html
视频讲解:https://www.bilibili.com/video/BV1ve4y1x7Eu/
1.1 初见思路
- 动规五部曲
- dp数组的定义:从左上角坐标为(0,0) ,dp[i][j]表示到达向右移动了i步,向下移动了j步的位置,的路径数量
- 确定转移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1];
- 确定初始化:dp[i][0]一定都是1,dp[0][j]同理
- 确定遍历顺序
- 举例推导dp数组
1.2 具体实现
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
dp[0][0]=1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0 || j==0){
dp[i][j]=1;
continue;
}
else{
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
}
1.3 重难点
二、 63. 不同路径 II
题目链接:https://leetcode.cn/problems/unique-paths-ii/
文章讲解:https://programmercarl.com/0063.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84II.html
视频讲解:https://www.bilibili.com/video/BV1Ld4y1k7c6/
2.1 初见思路
- 相对于上一题增加了中间的障碍物,应该没有太大区别,继续用动规五部曲来分析
- 确定dp[i,j]含义:左上角位(0,0)到达(i-1,j-1)坐标点有dp[i,j]条路径
- 确认转移方程:dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
但是要注意的是,遇到障碍物时dp[i][j]=0; - 确定初始化:dp[i][0]和dp[0][j]都是1,但是要注意,边路上有障碍的情况,不能把dp[i][0]和dp[0][j]都赋值为1,如果边路有障碍,那么障碍之后的边路应该都为0
- 确定顺序:
- 模拟
- 注意不要像上一题的写法,把赋予初始值跟计算路径数耦合在一起,这样写这道题很难写;
要把初始化和计算分开来。
2.2 具体实现
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int n = obstacleGrid[0].length;
int m = obstacleGrid.length;
int[][] dp = new int[m][n];
dp[0][0] = 1;
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];
}
}
2.3 重难点
三、343. 整数拆分
题目链接:https://leetcode.cn/problems/integer-break/description/
文章讲解:https://programmercarl.com/0343.%E6%95%B4%E6%95%B0%E6%8B%86%E5%88%86.html
视频讲解:https://www.bilibili.com/video/BV1Mg411q7YJ/
3.1 初见思路
- 看到题目中的“乘积最大化”,就应该想想是否要用动态规划
- 动规五部曲
- 确定dp[i]的含义:dp[i]表示就是将数字拆成 数字i 时的最大乘积
- 确定传递方程:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j))
不确定拆分的个数,怎么写这个方程?
j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘 - 初始化:dp[2]=1,之前的无意义
- 确定方向:从前向后遍历
- 模拟
3.2 具体实现
class Solution {
public int integerBreak(int n) {
int[] dp = new int[n + 1];
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= i - j; j++) {
// 这里的 j 其实最大值为 i-j,再大只不过是重复而已,
// 并且,在本题中,我们分析 dp[0], dp[1]都是无意义的,
// j 最大到 i-j,就不会用到 dp[0]与dp[1]
dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
// j * (i - j) 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘
// 而j * dp[i - j]是将 i 拆分成两个以及两个以上的个数,再相乘。
}
}
return dp[n];
}
}
3.3 重难点
- 确定传递方程是这题最难的地方