Java&LeetCode 初入门——174. 地下城游戏

Java&LeetCode 初入门——174. 地下城游戏

  • 题目
  • 个人解法

文内代码全部采用JAVA语言。

题目

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
Java&LeetCode 初入门——174. 地下城游戏_第1张图片

说明:

骑士的健康点数没有上限。
任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

测试用例

输入:[[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7

个人解法

很明显是动态规划问题。起初是正向求解,计算每一步的血量以及每一步所需要的最少起始血量,但是这样存在的问题也很明显:第i步走的时候,选择起始血量少但当前血量多的,还是选当前血量少,但起始血量多的。这将影响到下一步的操作。代码写完以后总有这样那样的测试用例通不过。
后来同学说可以从终点往起点走,只要保证不死,就行了,。与此同时,加血的过程变成掉血,掉血的过程变成加血,如果当前血量如果<=0,就将血量置1,这样可以最大限度保证最小血量还不死。

当前血量有两种走法,一种是从左边过来,一种是从下面上来。如果当前格是小怪兽,那么骑士会掉血,对于从终点来的骑士,就需要+|血量|(加上血量的绝对值),以保证他不会死,如果这一格有魔法球,骑士可以加血,那么到这一格所需要的血量就需要-当前元素值,如果减完发现骑士血量为负,就表示死着到这儿都行,但是血量必须>=1,所以为负的时候直接置1。

我觉得挺神奇的,从前往后看和从后往前看差距这么大。。。
附上代码,先检查两个边边(最下和最右)的血量,再检查中间的矩阵,原因是边边上只有一种走法。

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        int m=dungeon.length;
        int n=dungeon[0].length;
        int[][] blood=new int[m][n];
        if(dungeon[m-1][n-1]>=0){
            blood[m-1][n-1]=1;
        }else{
            blood[m-1][n-1]=1-dungeon[m-1][n-1];
        }
        for(int i=m-2;i>=0;i--){
            blood[i][n-1]=(blood[i+1][n-1]-dungeon[i][n-1])>0?(blood[i+1][n-1]-dungeon[i][n-1]):1;
        }
        for(int j=n-2;j>=0;j--){
            blood[m-1][j]=(blood[m-1][j+1]-dungeon[m-1][j])>0?blood[m-1][j+1]-dungeon[m-1][j]:1;
        }
        for(int i=m-2;i>=0;i--){
            for(int j=n-2;j>=0;j--){
                int left=blood[i+1][j]-dungeon[i][j]>0?blood[i+1][j]-dungeon[i][j]:1;
                int up=blood[i][j+1]-dungeon[i][j]>0?blood[i][j+1]-dungeon[i][j]:1;
                blood[i][j]=Math.min(left,up);
            }
        }
        return blood[0][0];
    }
}

执行用时 : 5 ms, 在Dungeon Game的Java提交中击败了65.38% 的用户
内存消耗 : 37.6 MB, 在Dungeon Game的Java提交中击败了79.86% 的用户

看了范例区的解法,大致思路都是一致的,有些小细节不同,不多赘述。

你可能感兴趣的:(Java&LeetCode 初入门——174. 地下城游戏)