66 * out in a 2D grid. Our valiant knight (K) was initially positioned in the
77 * top-left room and must fight his way through the dungeon to rescue the
88 * princess.
9- *
9+ * <p>
1010 * The knight has an initial health point represented by a positive integer. If
1111 * at any point his health point drops to 0 or below, he dies immediately.
12- *
12+ * <p>
1313 * Some of the rooms are guarded by demons, so the knight loses health
1414 * (negative integers) upon entering these rooms; other rooms are either empty
1515 * (0's) or contain magic orbs that increase the knight's health (positive
1616 * integers).
17- *
17+ * <p>
1818 * In order to reach the princess as quickly as possible, the knight decides to
1919 * move only rightward or downward in each step.
20- *
20+ * <p>
2121 * Write a function to determine the knight's minimum initial health so that he
2222 * is able to rescue the princess.
23- *
23+ * <p>
2424 * For example, given the dungeon below, the initial health of the knight must
2525 * be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.
26- *
26+ * <p>
2727 * -2(K) -3 3
2828 * -5 -10 1
2929 * 10 30 -5(P)
30- *
30+ * <p>
3131 * Notes:
3232 * The knight's health has no upper bound.
3333 * Any room can contain threats or power-ups, even the first room the knight
3434 * enters and the bottom-right room where the princess is imprisoned.
35- *
35+ * <p>
3636 * Tags:DP, Binary Search
3737 */
3838class DungeonGame {
39-
40- public static void main (String [] args ) {
41-
42- }
43-
44- /**
45- * Build a table for the minimum hp needed to get to the bottom right
46- * Build from bottom right to get minimum from i, j to the end
47- * Instead of build from to-left, because it's hard to get correct relation
48- */
49- public int calculateMinimumHP (int [][] dungeon ) {
50- if (dungeon == null || dungeon .length == 0 || dungeon [0 ].length == 0 ) return 0 ;
51- int m = dungeon .length - 1 ;
52- int n = dungeon [0 ].length - 1 ;
53- dungeon [m ][n ] = Math .max (1 - dungeon [m ][n ], 1 );
54- for (int i = m - 1 ; i >= 0 ; i --) dungeon [i ][n ] = Math .max (dungeon [i + 1 ][n ] - dungeon [i ][n ], 1 );
55- for (int j = n - 1 ; j >= 0 ; j --) dungeon [m ][j ] = Math .max (dungeon [m ][j + 1 ] - dungeon [m ][j ], 1 );
56- for (int i = m - 1 ; i >= 0 ; i --) {
57- for (int j = n - 1 ; j >= 0 ; j --) {
58- dungeon [i ][j ] = Math .max (Math .min (dungeon [i + 1 ][j ], dungeon [i ][j + 1 ]) - dungeon [i ][j ], 1 );
59- }
60- }
61- return dungeon [0 ][0 ];
39+
40+ /**
41+ * Build a table for the minimum hp needed to get to the bottom right
42+ * Build from bottom right to get minimum from i, j to the end
43+ * Instead of build from to-left, because it's hard to get correct relation
44+ */
45+ public int calculateMinimumHP (int [][] dungeon ) {
46+ if (dungeon == null || dungeon .length == 0 || dungeon [0 ].length == 0 ) return 0 ;
47+ int m = dungeon .length - 1 ;
48+ int n = dungeon [0 ].length - 1 ;
49+ dungeon [m ][n ] = Math .max (1 - dungeon [m ][n ], 1 );
50+ for (int i = m - 1 ; i >= 0 ; i --) dungeon [i ][n ] = Math .max (dungeon [i + 1 ][n ] - dungeon [i ][n ], 1 );
51+ for (int j = n - 1 ; j >= 0 ; j --) dungeon [m ][j ] = Math .max (dungeon [m ][j + 1 ] - dungeon [m ][j ], 1 );
52+ for (int i = m - 1 ; i >= 0 ; i --) {
53+ for (int j = n - 1 ; j >= 0 ; j --) {
54+ dungeon [i ][j ] = Math .max (Math .min (dungeon [i + 1 ][j ], dungeon [i ][j + 1 ]) - dungeon [i ][j ], 1 );
55+ }
6256 }
63- /**
64- * Why “from the bottom right corner to left top”?
65- * It depends on the way you formulate the problem. If you define a value
66- * in DP table d[i][j] as 'the minimum hp required to REACH (i, j) from (0,
67- * 0)", then the final answer should be d[nrows-1][ncols-1], and you need
68- * to start filling from the top left;
69- * However, in the reference answer provided with the question, dp[i][j] is
70- * defined as 'the minimum hp required to REACH (nrows-1, ncols-1) from (i,
71- * j)'. Here dp[0][0] is the final answer so we must fill from (nrows-1,
72- * ncols-1). For many other problems such as 'Minimum Path Sum', both
73- * formulation would work.
74- * However, in this problem, the former formulation will lead us to
75- * trouble, because it is very hard, if not impossible, to get d[i][j]
76- * based on d[i-1][j] and d[i][j-1].
77- */
57+ return dungeon [0 ][0 ];
58+ }
59+ /**
60+ * Why “from the bottom right corner to left top”?
61+ * It depends on the way you formulate the problem. If you define a value
62+ * in DP table d[i][j] as 'the minimum hp required to REACH (i, j) from (0,
63+ * 0)", then the final answer should be d[nrows-1][ncols-1], and you need
64+ * to start filling from the top left;
65+ * However, in the reference answer provided with the question, dp[i][j] is
66+ * defined as 'the minimum hp required to REACH (nrows-1, ncols-1) from (i,
67+ * j)'. Here dp[0][0] is the final answer so we must fill from (nrows-1,
68+ * ncols-1). For many other problems such as 'Minimum Path Sum', both
69+ * formulation would work.
70+ * However, in this problem, the former formulation will lead us to
71+ * trouble, because it is very hard, if not impossible, to get d[i][j]
72+ * based on d[i-1][j] and d[i][j-1].
73+ */
7874}
0 commit comments