力扣|力扣 - 剑指 Offer 47. 礼物的最大价值
题目
【力扣|力扣 - 剑指 Offer 47. 礼物的最大价值】剑指 Offer 47. 礼物的最大价值
思路1
- 因为是要求最大价值,而且只能移动下方或者右方,因此,每个位置的最大值就是
本身的值
加上上边 / 左边 中的最大值
,然后每次遍历都可以复用上一次的值。因此我们可以得到状态转移方程:- $ dp[i][j]=\begin{matrix} max(dp[i-1][j], dp[i][j-1]) + grid[i][j] \end{matrix} $
- 我们可以创建一个行和列都要多一行的 dp 数组,这样子可以不用判断条件了,但是同时也要注意
grid
中的坐标都要减去 1,因为我们是从 1 开始的:
class Solution {
public int maxValue(int[][] grid) {
int row = grid.length;
int col = grid[0].length;
// 创建dp数组,让 row 和 col 都多创建一行就可以避免判断边界值问题
int dp[][] = new int[row+1][col+1];
for (int i = 1;
i <= row;
i++) {
for (int j = 1;
j <= col;
j++) {
// 这里的 grid 中 i-1 和 j-1 是因为我们是从 1 开始的,所以要减去 1 才是原始正确的位置
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1];
}
}// 最后直接返回数组右下角值即可
return dp[row][col];
}
}
复杂度分析
- 时间复杂度:\(O(MN)\),
- 空间复杂度:\(O(MN)\),创建 dp 数组所花费的空间
- 然后我们可以优化一下,因为只能左走或者右走,因此第一行和第一列是固定的一条路,我们可以事先初始化计算一下第一行和第一列,到时就不用计算了。因此直接在原数组上直接进行就可以了
class Solution {
public int maxValue(int[][] grid) {
int row = grid.length;
int col = grid[0].length;
// 先初始化边界
for (int i = 1;
i < row;
i++) {
grid[i][0] += grid[i-1][0];
}
for (int i = 1;
i < col;
i++) {
grid[0][i] += grid[0][i-1];
}// 遍历
for (int i = 1;
i < row;
i++) {
for (int j = 1;
j < col;
j++) {
// 选择左边或者上边
grid[i][j] += Math.max(grid[i-1][j], grid[i][j-1]);
}
}// 最后直接返回数组右下角值即可
return grid[row-1][col-1];
}
}
复杂度分析
- 时间复杂度:\(O(MN)\),
- 空间复杂度:\(O(1)\),无需创建 dp 数组
推荐阅读
- 剑指|剑指 Offer 13. 机器人的运动范围(dfs,bfs)
- 数据结构与算法|【算法】力扣第 266场周赛
- leetcode|今天开始记录自己的力扣之路
- 剑指offer60.n个骰子的点数
- 剑指offer——最小的K个数
- Android|年后备战金三银四(Android面试吃透这一篇就没有拿不到的offer......)
- 剑指黄昏
- 剑指offer15.二进制中1的个数
- java|阿里工作8年,肝到P8就剩这份学习笔记了,已助朋友拿到10个Offer
- 字节前端面试经验(已拿到offer)