【Java】LeetCode 174. 地下城游戏 —— 困难

首先想到暴力解法,遍历每一条可能的路径,但是由于这个问题是指数型问题,暴力解法显然会因过于消耗资源以至于超时

那如果用空间换时间,维护一个同样大小的二维数组,用来存储“从起点到此处,最少扣多少血”呢?

乍一想好像很美好

但是请假设,有一条路径是:-100,-100,200,-1,-1

如果用上面的方法来计算,似乎整一条路径只要2点血,初始3血即可

可是,真实情况却是,我们的勇士,从第一个房间进去就GG了

为什么呢?

加血只能用来打后面的怪,你又不能欠血然后进加血房换回来(您以为血量这玩意还能打白条呢?)

这样的话,从起点出发似乎就行不通了

反过来想,如果从公主房往回退呢?

那么每一个数组元素应该存的是“从进这个之前房间一直到进入公主房间,我的血量要多少,才能保证我的血量不至于到0”

那么,怎么算呢?

基于我们只能往右或者往下走,也就是说,对于房间[i][j]来说,可以只关注[i+1][j]和[i][j+1]以及自己本身的值(打怪还是加血),从[i+1][j]和[i][j+1]出发所需要的最小血量,应该在之前已经计算出来

ij房间来说,如果这个房间是打怪,很简单,只要[i+1][j]和[i][j+1]中,较小值,加上ij房间中怪物血量就可以了

如果是加血呢,减少对应血量就行,但是要注意!再怎么减少,不能减少到0,否则可没有英雄不朽,这时就强制血量为1

整个过程大概如图

当然我实现的时候是先把最后一列和最后一行先算出来,然后再进行其余需要判断两边路径大小的位置,原理是一样的

class Solution {
          
   
    public int calculateMinimumHP(int[][] dungeon) {
          
   
        int a=dungeon.length,b=dungeon[0].length;
        int[][] hp=new int[a][b];
        //公主房间
        hp[a-1][b-1]=Math.max(1,-dungeon[a-1][b-1]+1);
        //计算最后一列
        for(int i=a-2;i>=0;i--){
          
   
            hp[i][b-1]=Math.max(1,hp[i+1][b-1]-dungeon[i][b-1]);
        }
        //计算最后一行
        for(int i=b-2;i>=0;i--){
          
   
            hp[a-1][i]=Math.max(1,hp[a-1][i+1]-dungeon[a-1][i]);
        }
        //计算剩下的
        for(int i=a-2;i>=0;i--){
          
   
            for(int j=b-2;j>=0;j--){
          
   
                hp[i][j]=Math.min(Math.max(1,hp[i+1][j]-dungeon[i][j]),Math.max(1,hp[i][j+1]-dungeon[i][j]));
            }
        }
        //返回初始房间血量
        return hp[0][0];
    }
}

当然由于这个算法是可以逐行或者逐列扫描的,甚至可以只存储单列或者单行

经验分享 程序员 微信小程序 职场和发展