[LeetCode] 174. Dungeon Game
The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.
The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.
Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).
In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.
Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.
For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN
.
-2 (K) | -3 | 3 |
-5 | -10 | 1 |
10 | 30 | -5 (P) |
Note:
- The knight's health has no upper bound.
- Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.
地下城游戏。题意是一个骑士需要从左上角的点移动到右下角的点去营救公主。为了节省时间,他决定只往下走或者往右走。在移动过程中,房间里面的数值会增加或者减少骑士的生命值,包括骑士一开始所处的房间和公主所处的房间。请返回骑士一开始最少需要的生命值以确保营救成功。
思路是动态规划。这道题dp[i][j]的定义是当骑士到(i, j)坐标时需要的最少生命值。一看到这道题目,就想到unique path类型的题目,但是这道题跟unique path的不同之处在于他给的是终点坐标的值,问的是起始值。我们一般做的动态规划的题目给的都是起始值,问的是终点坐标的值。既然这道题问的是最少的生命值,所以我们可以像做其他DP题一样,先创建一个二维数组,并且把所有的坐标都初始化为Integer.MAX_VALUE。这里有两处例外,就是dp[m - 1][n]和dp[m][n - 1],因为骑士在遇到终点dp[m][n]的时候,只会从这个点的上方或者左方过来,这两个点的dp值起码要等于1。接着从右下角往左上角扫描,每个点上的DP值是下方或者右方的一个较小的DP值 - 当前坐标上的生命值,同时这个DP值不能小于1。
时间O(mn)
空间O(mn)
Java实现
1 class Solution { 2 public int calculateMinimumHP(int[][] dungeon) { 3 // corner case 4 if (dungeon == null || dungeon.length == 0) { 5 return 0; 6 } 7 8 // normal case 9 int m = dungeon.length; 10 int n = dungeon[0].length; 11 int[][] dp = new int[m + 1][n + 1]; 12 for (int i = 0; i <= m; i++) { 13 Arrays.fill(dp[i], Integer.MAX_VALUE); 14 } 15 dp[m - 1][n] = 1; 16 dp[m][n - 1] = 1; 17 for (int i = m - 1; i >= 0; i--) { 18 for (int j = n - 1; j >= 0; j--) { 19 int minHp = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]; 20 if (minHp < 1) { 21 dp[i][j] = 1; 22 } else { 23 dp[i][j] = minHp; 24 } 25 } 26 } 27 return dp[0][0]; 28 } 29 }