【问题描述】[中等]
【解答思路】
1. 回溯(暴力)& 优化
超时,需要优化
public int calculateMinimumHP(int[][] dungeon) {if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {return 0;}int rowLen = dungeon.length;int colLen = dungeon[0].length;// 最低的耗血量为 + 1;就是骑士的救公主的最低血量。return dfs(0, 0, rowLen, colLen, dungeon) + 1;
}public int dfs (int rowIndex, int colIndex, int rowSize, int colSize, int[][] dungeon) {//if (rowIndex >= rowSize || colIndex >= colSize) {return Integer.MAX_VALUE;}// 退出条件if (rowIndex == rowSize - 1 && colIndex == colSize - 1) {if (dungeon[rowIndex][colIndex] >= 0) {// 如果最后一个大于等于0,就返还0。return 0;} else {//如果最后一个小于零,就返回负的值。return -dungeon[rowIndex][colIndex];}}
// 右边格子的最优解,也就是最低的耗血量int rightMin = dfs(rowIndex, colIndex + 1, rowSize, colSize, dungeon);
// 下边格子的最优解int downMin = dfs(rowIndex + 1, colIndex, rowSize, colSize, dungeon);// f(i,j) = min(f(i+1, j), f(i, j+1)) - dungeon[i][j]int needMin = Math.min(rightMin, downMin) - dungeon[rowIndex][colIndex];int res = 0;if (needMin < 0) {res = 0;} else {res = needMin;}System.out.println(rowIndex+ " "+colIndex + " " + res);return res;
}作者:fakerleet
链接:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/
private int rowSize = 0;
private int colSize = 0;
private int[][] globalDun = null;
public int calculateMinimumHP(int[][] dungeon) {if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {return 0;}rowSize = dungeon.length;colSize = dungeon[0].length;globalDun = dungeon;int[][] memory = new int[rowSize][colSize];// 初始化为-1,便于区别是否计算过结果了。for (int i = 0; i < rowSize; ++i) {for (int j = 0; j < colSize; ++j) {memory[i][j] = -1;}}return dfs(0, 0, memory) + 1;
}public int dfs (int rowIndex, int colIndex, int[][] memory) {if (rowIndex >= rowSize || colIndex >= colSize) {return Integer.MAX_VALUE;}// 不为-1就是计算过了,直接返回结果。if (memory[rowIndex][colIndex] != -1) {return memory[rowIndex][colIndex];}if (rowIndex == rowSize - 1 && colIndex == colSize - 1) {if (globalDun[rowIndex][colIndex] >= 0) {return 0;} else {return -globalDun[rowIndex][colIndex];}}int right = dfs(rowIndex, colIndex + 1, memory);int down = dfs(rowIndex + 1, colIndex, memory);int needMin = Math.min(right, down) - globalDun[rowIndex][colIndex];int res = 0;if (needMin < 0) {res = 0;} else {res = needMin;}memory[rowIndex][colIndex] = res;System.out.println(rowIndex+ " "+colIndex + " " + res);return res;
}作者:fakerleet
链接:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/
2. 动态规划
思路一:紧接上文
问:深搜过程中的记忆化,真的能保证走过的路径是最优的吗?比如第一次搜索经过[2,2]这个点,把结果记录下来。下次再次搜索的时候,起点可能不一样了,这个时候有没有可能计算结果对[2,2]产生更新呢?
答:dfs的递归本身就是逆推的
第一次搜索[2,2] 看起来是第一次搜索 其实已经是右和下方的回滚了
public int calculateMinimumHPBest(int[][] dungeon) {if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {return 0;}int rowSize = dungeon.length;int colSize = dungeon[0].length;int[][] dp = new int[rowSize][colSize];// 设置最后一个值。dp[rowSize - 1][colSize -1] = Math.max(0, -dungeon[rowSize - 1][colSize - 1]);// 设置最后一列的值for (int i = rowSize - 2; i >= 0; --i) {int needMin = dp[i + 1][colSize - 1] - dungeon[i][colSize - 1];dp[i][colSize -1] = Math.max(0, needMin);}// 设置最后一行的值for (int i = colSize - 2; i >= 0; --i) {int needMin = dp[rowSize - 1][i + 1] - dungeon[rowSize - 1][i];dp[rowSize - 1][i] = Math.max(0, needMin);}for (int i = rowSize - 2; i >= 0; --i) {for (int j = colSize - 2; j >= 0; --j) {// 从右边和下边选择一个最小值,然后减去当前的 dungeon 值int needMin = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];dp[i][j] = Math.max(0, needMin);}}return dp[0][0] + 1;
}作者:fakerleet
链接:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/
思路二:
class Solution {public int calculateMinimumHP(int[][] dungeon) {int n = dungeon.length, m = dungeon[0].length;int[][] dp = new int[n + 1][m + 1];for (int i = 0; i <= n; ++i) {Arrays.fill(dp[i], Integer.MAX_VALUE);}dp[n][m - 1] = dp[n - 1][m] = 1;for (int i = n - 1; i >= 0; --i) {for (int j = m - 1; j >= 0; --j) {int minn = Math.min(dp[i + 1][j], dp[i][j + 1]);dp[i][j] = Math.max(minn - dungeon[i][j], 1);}}return dp[0][0];}
}作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/dungeon-game/solution/di-xia-cheng-you-xi-by-leetcode-solution/
【总结】
1. 动态规划流程
第 1 步:设计状态
第 2 步:状态转移方程
第 3 步:考虑初始化
第 4 步:考虑输出
第 5 步:考虑是否可以状态压缩
2.思路 DFS -> 记忆化DFS->动态规划
转载:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/
参考:https://leetcode-cn.com/problems/dungeon-game/solution/di-xia-cheng-you-xi-by-leetcode-solution/