礼物的最大价值
题目:
在一个mxn的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格,知道到达棋盘的右下角。给定一个棋盘及其上面的礼物,请计算你最多能拿多少价值的礼物?
例如:对于如下棋盘,礼物的最大价值为 1+12+5+7+7+16+5=53。
1 10 3 8
12 2 9 6
5 7 4 11
3 7 16 5
分析:
- 利用循环的动态规划实现,使用辅助二维数组
定义f(i,j)表示到达坐标为(i,j)的格子时能拿到的礼物总和的最大值;
有两种路径到达(i,j):(i-1,j)或者(i,j-1);
f(i,j) = max(f(i-1,j), f(i,j-1)) + gift[i,j];
使用循环来计算避免重复子问题。
代码:
public int getMaxValueByArr(int[][] values, int rows, int cols) {
if (null == values || rows <= 0 || cols <= 0) {
return 0;
}
int[][] maxValue = new int[cols][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int up = 0;
int left = 0;
if (i > 0) {
up = maxValue[i - 1][j];
}
if (j > 0) {
left = maxValue[i][j - 1];
}
maxValue[i][j] = Math.max(up, left) + values[i][j];
}
}
return maxValue[rows - 1][cols - 1];
}
2. 优化空间复杂度,使用一维数组
- 题目中可知,坐标 (i,j) 的最大礼物价值仅仅取决于坐标为 (i-1,j) 和 (i,j-1) 两个格子;
- 因此第 i-2 行以上的最大价值没有必要保存下来。
- 使用一维数组保存:(0,0)…(0,j-1)保存的是(i,0)…(i,j-1)的最大价值;(0,j)…(0,cols-1)保存的是(i-1,j)…(i-1,cols-1)的最大价值。
- 每次计算新的(i,j)时,使用数组下标j-1和j的最大值加当前礼物值即可。
代码:
```java
public int getMaxValue(int[][] values, int rows, int cols) {
if (null == values || rows <= 0 || cols <= 0) {
return 0;
}
int[] maxValue = new int[cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int left = 0;
int up = 0;
if (i > 0) {
up = maxValue[j];
}
if (j > 0) {
left = maxValue[j - 1];
}
maxValue[j] = Math.max(left, up) + values[i][j];
}
}
return maxValue[cols - 1];
}