[Leetcode][第174题][JAVA][地下城游戏][DFS][动态规划]

╰半夏微凉° 2023-02-27 13:55 22阅读 0赞

【问题描述】[中等]

在这里插入图片描述

【解答思路】

在这里插入图片描述

1. 回溯(暴力)& 优化

在这里插入图片描述
在这里插入图片描述

超时,需要优化

  1. public int calculateMinimumHP(int[][] dungeon) {
  2. if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {
  3. return 0;
  4. }
  5. int rowLen = dungeon.length;
  6. int colLen = dungeon[0].length;
  7. // 最低的耗血量为 + 1;就是骑士的救公主的最低血量。
  8. return dfs(0, 0, rowLen, colLen, dungeon) + 1;
  9. }
  10. public int dfs (int rowIndex, int colIndex, int rowSize, int colSize, int[][] dungeon) {
  11. //
  12. if (rowIndex >= rowSize || colIndex >= colSize) {
  13. return Integer.MAX_VALUE;
  14. }
  15. // 退出条件
  16. if (rowIndex == rowSize - 1 && colIndex == colSize - 1) {
  17. if (dungeon[rowIndex][colIndex] >= 0) {
  18. // 如果最后一个大于等于0,就返还0。
  19. return 0;
  20. } else {
  21. //如果最后一个小于零,就返回负的值。
  22. return -dungeon[rowIndex][colIndex];
  23. }
  24. }
  25. // 右边格子的最优解,也就是最低的耗血量
  26. int rightMin = dfs(rowIndex, colIndex + 1, rowSize, colSize, dungeon);
  27. // 下边格子的最优解
  28. int downMin = dfs(rowIndex + 1, colIndex, rowSize, colSize, dungeon);
  29. // f(i,j) = min(f(i+1, j), f(i, j+1)) - dungeon[i][j]
  30. int needMin = Math.min(rightMin, downMin) - dungeon[rowIndex][colIndex];
  31. int res = 0;
  32. if (needMin < 0) {
  33. res = 0;
  34. } else {
  35. res = needMin;
  36. }
  37. System.out.println(rowIndex+ " "+colIndex + " " + res);
  38. return res;
  39. }
  40. 作者:fakerleet
  41. 链接:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/

在这里插入图片描述

  1. private int rowSize = 0;
  2. private int colSize = 0;
  3. private int[][] globalDun = null;
  4. public int calculateMinimumHP(int[][] dungeon) {
  5. if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {
  6. return 0;
  7. }
  8. rowSize = dungeon.length;
  9. colSize = dungeon[0].length;
  10. globalDun = dungeon;
  11. int[][] memory = new int[rowSize][colSize];
  12. // 初始化为-1,便于区别是否计算过结果了。
  13. for (int i = 0; i < rowSize; ++i) {
  14. for (int j = 0; j < colSize; ++j) {
  15. memory[i][j] = -1;
  16. }
  17. }
  18. return dfs(0, 0, memory) + 1;
  19. }
  20. public int dfs (int rowIndex, int colIndex, int[][] memory) {
  21. if (rowIndex >= rowSize || colIndex >= colSize) {
  22. return Integer.MAX_VALUE;
  23. }
  24. // 不为-1就是计算过了,直接返回结果。
  25. if (memory[rowIndex][colIndex] != -1) {
  26. return memory[rowIndex][colIndex];
  27. }
  28. if (rowIndex == rowSize - 1 && colIndex == colSize - 1) {
  29. if (globalDun[rowIndex][colIndex] >= 0) {
  30. return 0;
  31. } else {
  32. return -globalDun[rowIndex][colIndex];
  33. }
  34. }
  35. int right = dfs(rowIndex, colIndex + 1, memory);
  36. int down = dfs(rowIndex + 1, colIndex, memory);
  37. int needMin = Math.min(right, down) - globalDun[rowIndex][colIndex];
  38. int res = 0;
  39. if (needMin < 0) {
  40. res = 0;
  41. } else {
  42. res = needMin;
  43. }
  44. memory[rowIndex][colIndex] = res;
  45. System.out.println(rowIndex+ " "+colIndex + " " + res);
  46. return res;
  47. }
  48. 作者:fakerleet
  49. 链接: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] 看起来是第一次搜索 其实已经是右和下方的回滚了
在这里插入图片描述

  1. public int calculateMinimumHPBest(int[][] dungeon) {
  2. if (dungeon == null || dungeon.length == 0 || dungeon[0].length == 0) {
  3. return 0;
  4. }
  5. int rowSize = dungeon.length;
  6. int colSize = dungeon[0].length;
  7. int[][] dp = new int[rowSize][colSize];
  8. // 设置最后一个值。
  9. dp[rowSize - 1][colSize -1] = Math.max(0, -dungeon[rowSize - 1][colSize - 1]);
  10. // 设置最后一列的值
  11. for (int i = rowSize - 2; i >= 0; --i) {
  12. int needMin = dp[i + 1][colSize - 1] - dungeon[i][colSize - 1];
  13. dp[i][colSize -1] = Math.max(0, needMin);
  14. }
  15. // 设置最后一行的值
  16. for (int i = colSize - 2; i >= 0; --i) {
  17. int needMin = dp[rowSize - 1][i + 1] - dungeon[rowSize - 1][i];
  18. dp[rowSize - 1][i] = Math.max(0, needMin);
  19. }
  20. for (int i = rowSize - 2; i >= 0; --i) {
  21. for (int j = colSize - 2; j >= 0; --j) {
  22. // 从右边和下边选择一个最小值,然后减去当前的 dungeon 值
  23. int needMin = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];
  24. dp[i][j] = Math.max(0, needMin);
  25. }
  26. }
  27. return dp[0][0] + 1;
  28. }
  29. 作者:fakerleet
  30. 链接:https://leetcode-cn.com/problems/dungeon-game/solution/cong-hui-su-dao-ji-yi-hua-sou-suo-dao-dong-tai-gui/

思路二:
在这里插入图片描述
在这里插入图片描述

  1. class Solution {
  2. public int calculateMinimumHP(int[][] dungeon) {
  3. int n = dungeon.length, m = dungeon[0].length;
  4. int[][] dp = new int[n + 1][m + 1];
  5. for (int i = 0; i <= n; ++i) {
  6. Arrays.fill(dp[i], Integer.MAX_VALUE);
  7. }
  8. dp[n][m - 1] = dp[n - 1][m] = 1;
  9. for (int i = n - 1; i >= 0; --i) {
  10. for (int j = m - 1; j >= 0; --j) {
  11. int minn = Math.min(dp[i + 1][j], dp[i][j + 1]);
  12. dp[i][j] = Math.max(minn - dungeon[i][j], 1);
  13. }
  14. }
  15. return dp[0][0];
  16. }
  17. }
  18. 作者:LeetCode-Solution
  19. 链接: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/

发表评论

表情:
评论列表 (有 0 条评论,22人围观)

还没有评论,来说两句吧...

相关阅读

    相关 174. 地下游戏

    一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔