我的LeetCode代码仓:https://github.com/617076674/LeetCode
原题链接:https://leetcode-cn.com/problems/dungeon-game/description/
题目描述:
知识点:动态规划
思路:动态规划
如果从左上角算到右下角,本题的问题就是:在所有的路径中,选取一条路径,该路径中经过路径上每一点时骑士的生命值的最小值在所有路径中为最大。这个问题的求解极其复杂。
因此,我们选择从右下角算到左上角。
状态定义:
f(x, y) -------- 到达坐标(x, y)前骑士生命值的最小值
状态转移:
对于处于坐标(x, y)的骑士而言,其能到达的下一个位置是(x + 1, y)或(x, y + 1),如果(x + 1, y)和(x, y + 1)都没有越界的话。而到达(x + 1, y)或(x, y + 1)前骑士生命值的最小值是f(x + 1, y)和f(x, y + 1)。经过点(x, y),骑士将损耗dungeon[x][y]点生命值,因此f(x, y)的最小值应该是f(x + 1, y)和f(x, y + 1)中的较小者,再减去dungeon[x][y]。如果该值小于等于0,显然我们可以取f(x, y)为1,即最低生命值就能满足要求。
整个过程时从右下角算到左上角,当然算之前要先处理好边界情况,即(x + 1, y)或(x, y + 1)越界的情况,即数组的最后一行和最后一列。
时间复杂度和空间复杂度均是O(mn),其中m为地下城的行数,n为地下城的列数。
JAVA代码:
public class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int m = dungeon.length;
int n = dungeon[0].length;
int[][] hp = new int[m][n];
hp[m - 1][n - 1] = dungeon[m - 1][n - 1] >= 0 ? 1 : 1 - dungeon[m - 1][n - 1];
for(int i = m - 2; i >= 0; i--){
int temp = hp[i + 1][n - 1] - dungeon[i][n - 1];
hp[i][n - 1] = temp <= 0 ? 1 : temp;
}
for(int i = n - 2; i >= 0; i--){
int temp = hp[m - 1][i + 1] - dungeon[m - 1][i];
hp[m - 1][i] = temp <= 0 ? 1 : temp;
}
for(int i = m - 2; i >= 0; i--){
for(int j = n - 2; j >= 0; j--){
int temp = Math.min(hp[i + 1][j], hp[i][j + 1]) - dungeon[i][j];
hp[i][j] = temp <= 0 ? 1 : temp;
}
}
return hp[0][0];
}
}
LeetCode解题报告: