剑指 offer第47题-礼物的最大价值

在一个 m*n 的棋盘的每一个格都放有一个礼物,每个礼物都有一定价值(大于 0)。从左上角开始拿礼物,每次向右或向下移动一格,直到右下角结束。给定一个棋盘,求拿到礼物的最大价值。例如,对于如下棋盘

1 10 3 8
12 2 9 6
5 7 4 11
3 7 16 5

解题思路
应该用动态规划求解,而不是深度优先搜索,深度优先搜索过于复杂,不是最优解。
第一种方法,遍历二维数组,结果也是用二维数组来保存,

/* 初始数组的情况。
564 448 654 186 490 699
487 444 563 228 365 261
429 505 612 564 715 726
464 617 234 647 702 263
245 249 231 462 453 646
669 510 492 512 622 135
*/
/*结束后返回的数组。
564 1012 1666 1852 2342 3041
1051 1495 2229 2457 2822 3302
1480 2000 2841 3405 4120 4846
1944 2617 3075 4052 4822 5109
2189 2866 3306 4514 5275 5921
2858 3376 3868 5026 5897 6056
可以看到,最后一个坐标点的值6056,他就是当前最优的路径所得出来的值
*/
链接:https://www.nowcoder.com/questionTerminal/72a99e28381a407991f2c96d8cb238ab

public int getMost(int[][] board) { 
        //两个for循环用来遍历二维数组不用多说。
        for(int i = 0 ; i<board.length ; i++){
            for(int j = 0 ; j <board[0].length ; j++){
                if(i==0&&j==0){
                    //如果是起点坐标,不做任何处理。
                }else if(i == 0){
                    //如果走在行的临界边,也就是第一行,那么他只能向右走
                    //向右走的时候该点就要将后面的值加起来。
                    board[i][j] += board[i][j-1];
                }else if(j == 0){
                    //如果走在列的临界边,也就是第一列,那么他只能向下走
                    //向下走的时候该点就要将上面的值加起来。
                    board[i][j] += board[i-1][j];
                }else{
                    //核心点在这,除去两个临界边,剩下的就是既能向右走,也能向下走,
                    //那么这时候就要考虑走到当前点的所有可能得情况,也就是走到当前点
                    //各自路径的和是不是这些所有到达该点路径当中最大的了。
                    //temup用来存储从该点上面走下来的最大路径和。
                    //templeft用来存储从该点左边走过来的最大路径的和,
                    int temup = board[i-1][j];
                    int templeft = board[i][j-1];
                  //这两者肯定只能选其一,进行比较,那个大,就把这个值加给当前点,
                  //因为从一开始我们就进行了大小的比较,每一个点存储的都是到达当前点
                  //的最大值。所以直到最后一个点为止,她的值就是当前最大值的和。只要返回
                  //最后一个点的内容就可以了。
                    if(temup>templeft){
                        board[i][j] +=temup ;
                    }else{
                        board[i][j] +=templeft;
                    }
                }
            }
        }
       return  board[board.length-1][board[0].length-1];
    }

第二种方法,优化,用一维数组来保存结果:
先遍历二维数组当中的一维数组,以行为单位,一维数组的长度是列的长度。

1 10 3 8 dp-> 1 11 14 22
12 2 9 6 dp->13 15 24 30
5 7 4 11 dp->18 25 29 30
3 7 16 5 dp->21 32 48 53
dp[0]+=value[0];dp[0]累加
下一行的dp[i]和这一行的dp[i-1]和上一行的dp[i]取最大值,然后在加上此位置的value[i],
dp[i]=Math.max(dp[i],dp[i-1])+value[i];
最后一个数字就是礼物的最大值

import java.util.*;

public class Bonus {
    public int getMost(int[][] board) {
        // write code here
        if(board==null||board.length==0||board[0].length==0)
            return 0;
        int n=board[0].length;
        int[] dp=new int[n];
        for(int[] value:board)
        {
            dp[0]+=value[0];
            for(int i=1;i<n;i++){
                dp[i]=Math.max(dp[i],dp[i-1])+value[i];
            }
        }
        return dp[n-1];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值