题目来源:力扣
题目描述:
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
=============================================
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
===========================================
审题:
本题属于一道较简单的动态规划类题目.还是按照步骤一步步来分析.刚开始学习动态规划时,就像小时候解题一样,一步步理清自己的思路是非常重要的.按步骤慢慢来.
-
分析最优子结构
假设我们当前位于位置(i, j),我们想计算从该位置出发所能拿到的最多价值礼物, 由于我们每一步可以向右移动或向下移动,因此假设我们知道位置(i+1, j)以及位置(i, j+1)处我们所能拿到的最多价值礼物,我们便可以作出判断,在位置(i, j)处,我们应该向右还是向下移动. 基于该最优子结构,我们进一步分析子问题是否存在重叠. 分析不难发现, 为了计算(i, j)处最优方案,我们需要计算(i, j+1)处最优方案.而为了计算(i-1, j+1), 我们同样需要计算(i, j+1)处最优方案, 因此子问题存在重叠 -
分析状态变量
该问题状态变量较为简单, 即为当前所处位置. 由于是二维坐标, 因此我们可以使用二维数组存储每一状态处的最优方案. S[i][j]表示从位置(i, j)出发, 所能拿到的价值. -
确定状态转移方程
S [ i ] [ j ] = g r i d [ i ] [ j ] + m a x ( S [ i + 1 ] [ j ] , S [ i ] [ j + 1 ] ) S[i][j] = grid[i][j] + max(S[i+1][j], S[i][j+1]) S[i][j]=grid[i][j]+max(S[i+1][j],S[i][j+1])
其中基础情形为 S [ g r i d . l e n g t h − 1 ] [ g r i d [ 0 ] . l e n g t h − 1 ] = g r i d [ g r i d . l e n g t h − 1 ] [ g r i d [ 0 ] . l e n g t h − 1 ] S[grid.length-1][grid[0].length-1] = grid[grid.length-1][grid[0].length-1] S[grid.length−1][grid[0].length−1]=grid[grid.length−1][grid[0].length−1]
因此, 从左上角出发, 所能获取的最多价值礼物为S[0][0];
java算法:
class Solution {
public int maxValue(int[][] grid) {
//状态变量为当前位置
int S[][] = new int[grid.length][grid[0].length];
int row = grid.length;
int col = grid[0].length;
//基础情形
S[row-1][col-1] = grid[row-1][col-1];
for(int i = row-1; i >= 0; i--){
for(int j = col-1; j >= 0; j--){
if(i + 1 < row){
S[i][j] = Math.max(S[i][j], grid[i][j] + S[i+1][j]);
}
if(j+1 < col){
S[i][j] = Math.max(S[i][j], grid[i][j] + S[i][j+1]);
}
}
}
return S[0][0];
}
}
降低空间复杂度值O(1)
在初始版本中,由于我们使用额外的数组S保存各状态时的最优方案, 因此空间复杂度为O(MN). 通过分析, 我们发现我们可以直接更改grid[i][j]上的元素, 在计算完(i, j)处最优方案后,使用grid[i][j]储存位置(i, j)处最优方案.
class Solution {
public int maxValue(int[][] grid) {
//状态变量为当前位置
//int S[][] = new int[grid.length][grid[0].length];
int row = grid.length;
int col = grid[0].length;
for(int i = row-1; i >= 0; i--){
for(int j = col-1; j >= 0; j--){
int sum = 0;
if(i + 1 < row){
sum = Math.max(sum, grid[i+1][j]);
}
if(j+1 < col){
sum = Math.max(sum,grid[i][j+1]);
}
grid[i][j] += sum;
}
}
return grid[0][0];
}
}