标签:维数 math 回溯 存在 获得 提交 created 条件 多少
在一个 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
该问题也是一个动态规划的思想的重要体现。但是先谈谈暴力方法的,很直接,我们可以通过迭代遍历所有存在的路径的可能性,然后记录每个路径的最大值然后获得最终的最大值。这也是我第一时间象到的方法,具体实现参考我的代码Solution。
这里简单的通过分析我们迭代法的问题,迭代法不论该路径是不是最大值的可能性,通过迭代和回溯中把所有的可能的路径都走一边,逻辑如下:
说是动态规划,其实就是空间换时间,通过遍历所有格子,根据该格子的上面位置最大礼物价值与左侧礼物价值来计算本格子的最大礼物价值,记录下路来每个格子的最大礼物价值,然后知道右下角为止。动态思想的规划如下:
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] //
标签:维数 math 回溯 存在 获得 提交 created 条件 多少
原文地址:https://www.cnblogs.com/dazhu123/p/12607015.html