礼物的最大价值
Posted dazhu123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了礼物的最大价值相关的知识,希望对你有一定的参考价值。
1:题目描述
在一个 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
通过次数6,906提交次数10,312
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2:题目分析
2.1:暴力法
该问题也是一个动态规划的思想的重要体现。但是先谈谈暴力方法的,很直接,我们可以通过迭代遍历所有存在的路径的可能性,然后记录每个路径的最大值然后获得最终的最大值。这也是我第一时间象到的方法,具体实现参考我的代码Solution。
这里简单的通过分析我们迭代法的问题,迭代法不论该路径是不是最大值的可能性,通过迭代和回溯中把所有的可能的路径都走一边,逻辑如下:
- 迭代终止条件:遇到右下位置,或者超过数组边界,遇到右下位置则,直接记录当前路径的价值和,记录下拉,与其它路径比较,保存最大值
- 迭代逻辑:将当前礼物价值加到sum里,然后向右迭代,然后再下迭代,为了当回溯的时候能够有效开启其他路径,我们回溯的时候要把本次加上的礼物值给减去,见代码
- 返回值:void
2.2:动态规划法
说是动态规划,其实就是空间换时间,通过遍历所有格子,根据该格子的上面位置最大礼物价值与左侧礼物价值来计算本格子的最大礼物价值,记录下路来每个格子的最大礼物价值,然后知道右下角为止。动态思想的规划如下:
- 状态的定义:由于是获取最大礼物价值,我们不得不对所有位置的礼物价值都要考核进行,所以我们定义一个与棋盘等大的二维数组,存放从左上开始到该位置的最大礼物价值数。int[][] dp = new int[grid.length][grid[0].length]
- 转移方程:我们分析我们定义的dp状态,发现该位置礼物最大值为上和左两个位置礼物最大的那一个加上该礼物的礼物值。分析发现 第0行和第0列处的最大礼物值为左侧最大礼物值加上本地和上侧最大礼物值加上本地,非边位置的最大礼物值为上左中的最大值加上本地礼物值。
- 返回值:该位置的最大礼物值。
3:代码示例
package JianZhiOffer47; /** * @author :dazhu * @date :Created in 2020/3/31 16:28 * @description:剑指offer47 * @modified By: * @version: $ */ public class Main { public static void main(String[]args){ int[][] arr = new int[][]{ {1,3,1}, {1,5,1}, {4,2,1} }; Solution1 solution = new Solution1(); System.out.println(solution.maxValue1(arr)); } } //也不做dp了,因为dp没法确定状态转移方程,从而更新bp,直接暴力搜索出所有路径,拿出最大的一个 class Solution { int sum = 0; int sumResult = 0; public int maxValue(int[][] grid) { recur(grid,0,0); return sumResult; } //迭代终止条件:到达终点停止,都在一致向右向下走下去。 //迭代逻辑:礼物值加上当前值,先向右,再向左走 //返回值:当前位置的礼物值 public void recur(int[][] grid,int i,int j) { //终止条件:i和j越界 if((i > grid.length-1)||(j > grid[0].length-1)) { return ; } //终止条件:如果达到重点,则比较判断保存最大值 if((i == grid.length-1)&&(j == grid[0].length-1)) { sum = sum + grid[i][j]; if(sum >sumResult){ sumResult = sum; } sum = sum - grid[i][j]; return ; } //迭代逻辑 sum = sum + grid[i][j]; //先向右 recur(grid,i,j+1); //再向下 recur(grid,i+1,j); //回溯时,减去本值,为了新的路径准备 sum = sum - grid[i][j]; } } //上面暴力的方法速度太慢也不是解决该问题的最佳方法 //我们采用!dp的思想考虑这个问题,下面 //状态定义:由于范围时二维棋盘,且存在有些位置价值不同,顺序不同,针对每一个点都计算出,从 //出发点到该点的最大的价值,用dp[][]二维数组记录下来 //状态转移方程:dp[i][j] = max(dp[i-1][j] ,dp[i][j-1]) + arr[i][j] //返回值:返回该位置的最大礼物价值 class Solution1 { int[][] dp = null; public int maxValue1(int[][] grid) { int i = 0; int j = 0; //暂存结果的二维数组 dp = new int[grid.length][grid[0].length]; //控制转移方向,一步一步向目标移动 //从上到下,从左到右。 for(i=0;i<grid.length;i++){ for(j=0;j<grid[0].length;j++){ //第一行为只有左侧有礼物 if(i == 0){ //如果是第0行,第0列, if(j == 0){ dp[i][j] = grid[i][j]; } else{ //第0行,非0列,为左点位置的最大礼物数加上该位置礼物值 dp[i][j] = dp[i][j-1] + grid[i][j]; } } //第一列为只有上侧有礼物 if(j == 0){ //如果是第0行,第0列, if(i == 0){ dp[i][j] = grid[i][j]; } else{ //非0行,第0列,上点位置的最大礼物数加上该位置礼物值 dp[i][j] = dp[i-1][j] + grid[i][j]; } } //非0行,非0列的最大礼物值为,从上,左中选择最大的礼物价值,然后加上本身位置 if((j != 0)&&(i != 0)) { dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; } } } return dp[i-1][j-1]; } } // // [1,3,5,2], // [1,5,1,2], // [70,2,1,1] //
以上是关于礼物的最大价值的主要内容,如果未能解决你的问题,请参考以下文章