【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]; } }
当然由于这个算法是可以逐行或者逐列扫描的,甚至可以只存储单列或者单行
上一篇:
Java基础知识总结(2021版)
下一篇:
垃圾收集算法——新生代和老年代(JVM)