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.
Idea: With a few simple equations, we can solve this problem easily. Let us use dp[i][j] to denote the minimum health needed to start from block (i,j) (including entering (i,j)) then go to (m-1, n-1), where m is the number of rows, n is the number of columns. We have the following equations:
(1) dp[i][j]>=1, since dp[i][j] can not be 0 or below anytime, even before entering any block.
(2) dp[i][j]+dungeon[i][j]>=1, since the knight's health should be at least 1 after entering the block[i][j].
(3) dp[i][j]+dungeon[i][j]>=dp[i+1][j], since the knight's health should be enough to start from the block under [i][j]
(4) dp[i][j]+dungeon[i][j]>=dp[i][j+1], since the knight's health should be enough to start from the next block on the right of [i][j].
In any case, equation (1) and equation (2) are required to be fulfilled. However, either (3) or (4) works, the knight can succeed. By moving the items on the left of equations (1) - (4) except dp[i][j] to the right, we have
(5) dp[i][j]>=1
(6) dp[i][j]>=1- dungeon[i][j]
(7) dp[i][j]>= dp[i+1][j]-dungeon[i][j] OR dp[i][j+1]-dungeon[i][j].
Since we need to minimize the health needed, we take the minimum of the two routes in the equation (7). Then we have the final equation:
(8) dp[i][j]= maxOfThree(1, 1- dungeon[i][j], Math.min(dp[i+1][j]-dungeon[i][j], dp[i][j+1]-dungeon[i][j])).
For the dp blocks at dp[m-1][n-1], the last row and the last column, just remove the items out of the boundary.
Time: O(n^2) Space: O(n^2)
Code:
public class Solution {
public int calculateMinimumHP(int[][] dungeon) {
if(dungeon.length==0||dungeon[0].length==0)
return 0;
int m=dungeon.length;
int n=dungeon[0].length;
int[][] dp=new int[m][n];
dp[m-1][n-1]=Math.max(1, 1- dungeon[m-1][n-1]);
for(int j=n-2;j>=0;j--)
dp[m-1][j]=maxOfThree(1, 1-dungeon[m-1][j],-dungeon[m-1][j]+dp[m-1][j+1]);
for(int i=m-2;i>=0;i--)
dp[i][n-1]=maxOfThree(1, 1-dungeon[i][n-1],-dungeon[i][n-1]+dp[i+1][n-1]);
for(int i=m-2;i>=0;i--)
{
for(int j=n-2;j>=0;j--)
{
dp[i][j]=maxOfThree(1, 1-dungeon[i][j], Math.min(-dungeon[i][j]+dp[i+1][j], -dungeon[i][j]+dp[i][j+1]));
}
}
return dp[0][0];
}
public int maxOfThree(int a, int b, int c)
{
return Math.max(Math.max(a,b),c);
}
}
No comments:
Post a Comment