题目
算法思路
设
v
a
l
u
e
(
i
,
j
)
value(i,j)
value(i,j) 表示单元格
(
i
,
j
)
(i,j)
(i,j) 的礼物价值,
f
(
i
,
j
)
f(i,j)
f(i,j) 表示从棋盘左上角走到单元格
(
i
,
j
)
(i,j)
(i,j) 的礼物最大价值,显然有转移方程:
f
(
i
,
j
)
=
m
a
x
{
f
(
i
−
1
,
j
)
,
f
(
i
,
j
−
1
)
}
+
v
a
l
u
e
(
i
,
j
)
f(i,j)=max\{f(i-1,j),\ f(i,j-1) \}+value(i,j)
f(i,j)=max{f(i−1,j), f(i,j−1)}+value(i,j)
初始状态:
f
(
0
,
0
)
=
v
a
l
u
e
(
0
,
0
)
f(0,0)=value(0,0)
f(0,0)=value(0,0)
边界处理:
- 当
i == 0 && j != 0
时,为矩阵第一行元素,只能从左边到达: f ( i , j ) = f ( i , j − 1 ) + v a l u e ( i , j ) f(i,j)=f(i,j-1)+value(i,j) f(i,j)=f(i,j−1)+value(i,j) - 当
i != 0 && j == 0
时,为矩阵第一列元素,只能从上边到达: f ( i , j ) = f ( i − 1 , j ) + v a l u e ( i , j ) f(i,j)=f(i-1,j)+value(i,j) f(i,j)=f(i−1,j)+value(i,j)
返回值: f ( m − 1 , n − 1 ) f(m-1,n-1) f(m−1,n−1),其中 m,n 为矩阵的行数和列数
注意:由于 f ( i , j ) f(i,j) f(i,j) 只与 f ( i − 1 , j ) f(i-1,j) f(i−1,j)、 f ( i , j − 1 ) f(i,j-1) f(i,j−1)、 v a l u e ( i , j ) value(i,j) value(i,j) 有关,所以可以直接在原矩阵上修改,省去了额外的矩阵空间。
具体代码
class Solution {
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(i == 0 && j == 0)continue;
if(i == 0)grid[i][j] += grid[i][j - 1];//第一行
else if(j == 0)grid[i][j] += grid[i - 1][j];//第一列
else grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]);
}
}
return grid[m - 1][n - 1];
}
}
代码改进
当矩阵规模很大时,为第一行或列的情况只占极少数,几乎循环的每一轮都冗余了一次判断。可以先初始化第一行和第一列,然后再遍历矩阵。
class Solution {
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
for(int j = 1; j < n; j++){//初始化第一行
grid[0][j] += grid[0][j - 1];
}
for(int i = 1; i < m; i++){//初始化第一列
grid[i][0] += grid[i - 1][0];
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]);
}
}
return grid[m - 1][n - 1];
}
}
复杂度分析
- 时间复杂度: O ( m n ) O(mn) O(mn),其中 m,n 为矩阵的行数和列数
- 空间复杂度: O ( 1 ) O(1) O(1)