在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 ,可以拿到最多价值的礼物
方法:动态规划法,使用双指针两层循环,从尾至首循环遍历。
n,m为遍历序号最大值:m = len(grid)-1
, n = len(grid[0])-1
。
初始化dp= grid 。
状态定义:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为在
(
i
,
j
)
(i,j)
(i,j)处能拿到的最大价值。
转移方程:
d
p
[
i
]
[
j
]
=
d
p
[
i
]
[
j
]
+
m
a
x
(
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
]
[
j
+
1
]
)
dp[i][j] = dp[i][j] + max(dp[i+1][j], dp[i][j+1])
dp[i][j]=dp[i][j]+max(dp[i+1][j],dp[i][j+1]),此处需要注意行列的边界。
初始状态:
d
p
[
m
]
[
n
]
=
g
r
i
d
[
m
]
[
n
]
dp[m][n] = grid[m][n]
dp[m][n]=grid[m][n]
返回值:
d
p
[
0
]
[
0
]
dp[0][0]
dp[0][0]
如下图所示逐行遍历:
最终得到二维dp表
需要注意:
- 当遍历遇到边界最后一行时: d p [ i ] [ j ] = d p [ i ] [ j ] + d p [ i ] [ j + 1 ] dp[i][j] = dp[i][j] + dp[i][j+1] dp[i][j]=dp[i][j]+dp[i][j+1]
- 当遍历遇到边界最后一列时: d p [ i ] [ j ] = d p [ i ] [ j ] + d p [ i + 1 ] [ j ] dp[i][j] = dp[i][j] + dp[i+1][j] dp[i][j]=dp[i][j]+dp[i+1][j]
- 当遇见最后一个数 g r i d [ m ] [ n ] grid[m][n] grid[m][n]时:直接跳过此循环,因为之前赋值 d p = g r i d dp= grid dp=grid时,就已经令 d p [ m ] [ n ] = g r i d [ m ] [ n ] dp[m][n] = grid[m][n] dp[m][n]=grid[m][n]了。
Python
class Solution:
def maxValue(self, grid: List[List[int]]) -> int:
if grid == []: return 0
m = len(grid)-1
n = len(grid[0])-1
dp = grid
for i in range(m, -1, -1):
for j in range(n, -1, -1):
if i == m and j == n: continue
elif i == m: dp[i][j] = dp[i][j] + dp[i][j+1]
elif j == n: dp[i][j] = dp[i][j] + dp[i+1][j]
else: dp[i][j] = dp[i][j] + max(dp[i+1][j], dp[i][j+1])
return dp[0][0]
一遍过