JZ47 礼物的最大价值

JZ47 礼物的最大价值

描述

在一个$m×n$的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

如输入这样的一个二维数组,

1
2
3
4
5
[
[1,3,1],
[1,5,1],
[4,2,1]
]

那么路径 $1\to3\to5\to2\to1$ 可以拿到最多价值的礼物,价值为12

示例1

1
2
输入:[[1,3,1],[1,5,1],[4,2,1]]
返回值:12

备注

$0<grid.length≤200 $
$0<grid[0].length≤200$

题解

同样的,拆解问题,我们只能考虑从左上角向右还是向下移动,直到到达右下角,所以每一次的操作只能考虑向右还是下移动。反过来也可以考虑从右下角往左上移动,二者是相似的,重点在于如何找到那条值的和最大的路径。

到达某个位置的礼物价值最大和是一定的,设为$dp[i][j]$,那么$dp[i][j]=max(dp[i-1][j],dp[i][j-1])+grid[i][j]$

由于到达最上方一列和最左侧一列都只有一条路径,那么可以获得初始条件:
$$
dp[i][0]=\sum_{k=0}^{i}grid[k][0]\
dp[0][j]=\sum_{k=0}^{j}grid[0][k]
$$
最后可以由递归直接获得$dp[m][n]$返回即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param grid int整型vector<vector<>>
* @return int整型
*/
int maxValue(vector<vector<int> >& grid) {
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> dp(m, vector<int>(n));
//初始化
dp[0][0] = grid[0][0];
for(int i = 1; i < m; i++){
dp[i][0] = grid[i][0] + dp[i-1][0];
}
for(int i = 1; i < n; i++){
dp[0][i] = grid[0][i] + dp[0][i-1];
}
//递推
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = max(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[m-1][n-1];
}
};

没想出来怎么优化,问了大G老师,大G老师说把二维数组$dp$压成一维数组,看完了懂了,在遍历过程中,实际上只需要上一行的信息以及左侧一个的信息即可,上一行的信息用$dp_pre$存储,左侧一个的用$left$存储即可。