题目描述
众所周知,牛妹有很多很多粉丝,粉丝送了很多很多礼物给牛妹,牛妹的礼物摆满了地板。
地板是N\times MN×M的格子,每个格子有且只有一个礼物,牛妹已知每个礼物的体积。
地板的坐标是左上角(1,1) 右下角(N, M)。
牛妹只想要从屋子左上角走到右下角,每次走一步,每步只能向下走一步或者向右走一步或者向右下走一步
每次走过一个格子,拿起(并且必须拿上)这个格子上的礼物。
牛妹想知道,她能走到最后拿起的所有礼物体积最小和是多少?
题目链接
一道简单的动态规划入门题。
对于之前没有接触过动归的人,动归的题往往让然看起来不知道从何下手。
前两天在b站看了一个up讲的动态规划让我这种之前没有系统学习过动归的有了更深的理解,up叫正月点灯笼,大家感兴趣的可以去看看。
我觉得动归很多时候都是一个我们要在解决问题的时候找到每一步最好的选择的过程。
如果只走一步,走到2。我们有三种走法,从1走到2或者从6走到2,或者从8走到2。其中最好的选择时从1走到2。
换句话说,只走一步的情况下,我们可以找到走到2的最优解。可是实际上会有更多的格子。
这时候我们如果仍然是从左上角出发把2作为目的地的话,那么通过1走到2就不在是最好的选择了。
那么我们怎么可以把这个局部的最优解扩大到全局,获得我们的最终想要的结果呢?
其实很简单,就是保证我们从左上角出发开始,选择走的每一步都是最优解即可。
我们不难发现想要走到蓝色的部分只能是来自他的上方或者左方。我们可以求出蓝色部分的最优解。
举例:
剩下的格子的最优解就是从它的上方、左方、左上方中选择负重最小的。
这样当我们走到最后一个格子的时候就求出了最优解。
代码如下:
import java.util.*;
public class Solution {
/**
*
* @param presentVolumn int整型二维数组 N*M的矩阵,每个元素是这个地板砖上的礼物体积
* @return int整型
*/
public int selectPresent (int[][] presentVolumn) {
// write code here
if(presentVolumn.length == 0) {
return 0;
}
int[][] ret = presentVolumn;
//初始化第一行第一列的最优解
if(ret[0].length > 1) {
for (int i = 1; i < ret[0].length; i++) {
ret[0][i] += ret[0][i - 1];
}
}
if(ret.length > 1) {
for (int i = 1; i < ret.length; i++) {
ret[i][0] += ret[i - 1][0];
}
}
if(ret.length == 1) {
return ret[0][ret[0].length - 1];
}
if(ret[0].length == 1) {
return ret[ret.length - 1][0];
}
for (int i = 1; i < ret.length; i++) {
for (int j = 1; j < ret[0].length; j++) {
ret[i][j] += Integer.min(ret[i - 1][j - 1], Integer.min(ret[i - 1][j], ret[i][j - 1]));
}
}
return ret[ret.length - 1][ret[0].length - 1];
}
}
代码中需要注意的几点:1.用例中会有presentVolumn.length == 0的情况,需要单独处理或者会报出越界。
2.需要考虑到只有一行或者只有一列的特殊情况。
3.在二维数组中行的长度=有多少列 列的长度=有多少行
希望可以帮助你,觉得还不错的话点个赞吧。