通俗易懂的帮你解决 剑指 Offer 47. 礼物的最大价值

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

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

输入:

[

[1,3,1],

[1,5,1],

[4,2,1]

]

输出: 12

解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物

解题思路

  • 根据题意我们可以得到信息,从左上角到右下角路过的每个位置的和最大,也就是我们要求的最大价值的礼物。

  • 本体属于动态规划的题,就是下一步要进行什么与上一步的结果有关系,本题跟最经典的0-1背包问题其实是差不多的。

  • 我们需要创建一个dp数组,大小跟原数组大小相等

算法流程

  1. 动态规划:(动态规划五部曲)

  1. 确定dp数组以及下标的含义

dp[i] [j]的定义为:第(i,j)位置能得到最大礼物价值。

  1. 确定递推公式

我们可以从两个方向推出来dp[i] [j],推出dp[i] [j] 与dp[i] [j] 上方以及dp[i] [j] 左边的值有关,当dp[i] [j] 上方值大于左边值,那么dp[i] [j] = dp[i - 1] [j] + grid[i] [j];

所以递推公式: dp[i] [j] = Math.max(dp[i] [j - 1], dp[i - 1] [j]) + grid[i] [j];

  1. dp数组如何初始化

  • 针对于第一行跟第一列,每走到下一个位置,下一个位置最大礼物价值就是该位置与上一个位置数相加。(因为第一行只能一直向右走,第一列只能一直向下走。)

  • 对于其他位置:

我们可以看递推公式:dp[i] [j] = Math.max(dp[i] [j - 1], dp[i - 1] [j]) + grid[i] [j]; 很明显每个位置与上方或左边位置的值有关,还有最初数组该位置有关,dp数组这个位置没关系,所以初始化为几都可以,当然我们为了方便直接初始化为0;

  • 初始化数组如图所示:

  1. 确定遍历顺序

本题遍历可以先遍历行再遍历列,也可以先遍历列再遍历行。

针对我们日常习惯,我选择先遍历行。

        for(inti=1; i<grid.length; i++){
            for(intj=1; j<grid[0].length; j++){
                dp[i][j] =Math.max(dp[i][j-1], dp[i-1][j]) +grid[i][j];
            }
        }

  1. 举例推导dp数组

来看一下对应的dp数组的数值,如图:

最终结果就是dp[2] [2].

完整java代码

classSolution {
    publicintmaxValue(int[][] grid) {
        if(grid.length==0) return0;
        int[][] dp=newint[grid.length][grid[0].length];
        dp[0][0] =grid[0][0];
        for(inti=1; i<grid[0].length; i++){
            dp[0][i] =grid[0][i] +dp[0][i-1]; 
        }
        for(inti=1; i<grid.length; i++){
            dp[i][0] =grid[i][0] +dp[i-1][0];
        }
        for(inti=1; i<grid.length; i++){
            for(intj=1; j<grid[0].length; j++){
                dp[i][j] =Math.max(dp[i][j-1], dp[i-1][j]) +grid[i][j];
            }
        }
        returndp[grid.length-1][grid[0].length-1];
    }
}

大致流程分析图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值