难度:中等
在一个 m * n
的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。
你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。
给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
####示例 1:
输入:
[ [1,3,1], [1,5,1], [4,2,1] ]
输出:
12
解释: 路径1→3→5→2→1
可以拿到最多价值的礼物
提示:
0 < grid.length <= 200
0 < grid[0].length <= 200
应该用动态规划求解,而不是深度优先搜索,深度优先搜索过于复杂,不是最优解。
从棋盘的左上角开始拿格子里的礼物,并每次 向右 或者 向下 移动一格、直到到达棋盘的右下角。 根据题目说明,易得某单元格只可能从上边单元格或左边单元格到达。
设 dp[i,j]
为从棋盘左上角走至单元格 [i,j]
的礼物最大累计价值,易得到以下递推关系:dp[i,j]
等于 dp[i,j−1]
和 dp[i−1,j]
中的较大值加上当前单元格礼物价值 grid[i,j]
,状态转移方程为:
d p [ i , j ] = { g r i d [ i , j ] , i = 0 , j = 0 g r i d [ i , j ] + d p [ i , j − 1 ] , i = 0 , j ≠ 0 g r i d [ i , j ] + d p [ i − 1 , j ] , i ≠ 0 , j = 0 g r i d [ i , j ] + max ( d p [ i − 1 , j ] , d p [ i , j − 1 ] ) , i ≠ 0 , j ≠ 0 dp[i,j]=\begin{cases}grid[i,j]&,i=0,j=0\\grid[i,j]+dp[i,j-1]&,i=0,j\neq0\\grid[i,j]+dp[i-1,j]&,i\neq0,j=0\\grid[i,j]+\max(dp[i-1,j],dp[i,j-1])&,i\neq0,j\neq0\end{cases} dp[i,j]=⎩ ⎨ ⎧grid[i,j]grid[i,j]+dp[i,j−1]grid[i,j]+dp[i−1,j]grid[i,j]+max(dp[i−1,j],dp[i,j−1]),i=0,j=0,i=0,j=0,i=0,j=0,i=0,j=0
空间优化:
dp[i][j]
只与 dp[i−1][j]
, dp[i][j−1]
, grid[i][j]
有关系,因此可以将原矩阵 grid
用作 dp
矩阵,即直接在 grid
上修改即可。dp
矩阵使用的额外空间,因此空间复杂度从 O ( m n ) O(mn) O(mn) 降至 O ( 1 ) O(1) O(1) 。C++
class Solution {
public:
int maxValue(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
for(int i = 1; i < m; i++){ // 先处理第一行
grid[i][0] += grid[i - 1][0];
}
for(int i = 1; i < n; i++){ //处理第一行列
grid[0][i] += grid[0][i - 1];
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
grid[i][j] += max(grid[i - 1][j], grid[i][j - 1]);
}
}
return grid[m - 1][n - 1];
}
};
Java
class Solution {
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
for(int i = 1; i < m; i++){//先处理第一行
grid[i][0] += grid[i - 1][0];
}
for(int i = 1; i < n; i++){//处理第一列
grid[0][i] += grid[0][i - 1];
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
}
}
return grid[m - 1][n - 1];
}
}
m
和 n
分别为二维数组 grid
的行高、列宽,动态规划需遍历整个 grid
。题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!