剑指 Offer 47. 礼物的最大价值

在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

示例 1:

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 ,可以拿到最多价值的礼物

方法:动态规划法,使用双指针两层循环,从尾至首循环遍历。
n,m为遍历序号最大值:m = len(grid)-1n = len(grid[0])-1
初始化dp= grid 。
状态定义: d p [ i ] [ j ] dp[i][j] dp[i][j]为在 ( i , j ) (i,j) ij处能拿到的最大价值。
转移方程: 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表
在这里插入图片描述
需要注意:

  1. 当遍历遇到边界最后一行时: 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]
  2. 当遍历遇到边界最后一列时: 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]
  3. 当遇见最后一个数 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]

在这里插入图片描述

一遍过

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值