leetcode Java:174. 地下城游戏

题目174. 地下城游戏

思路:动态规划。

假设有一条路径:-2,-5,10,30,-5。

如果正向找初始值,我们需要存两个值,满足需求的起点健康值和达到每个位置时需要的最少健康值:
在这里插入图片描述
每个位置需要的最少健康值依赖前一个位置;满足需求的起点健康值就是在每个位置需要的最少健康值中取最大的(1也参与比较,因为有可能路径全为正值)。

如果反向找:下图从右到左看。我们无需额外计算起点健康值,在起点处的值就是我们想要的答案。
在这里插入图片描述
所以,我们动态规划是从终点开始搜索。

dp[i][j]表示坐标(i,j)到达终点需要的健康点。
由于只能向右或向下走,我们填充dp[i][j]数组就依赖dp[i + 1][j]dp[i][j + 1],二者取较小的;然后再加上坐标(i,j)消耗的点数;最后和1比较取较大的(路径正值)。

综上,转移方程:

dp[i][j] = Math.max(Math.min(dp[i + 1][j], dp[i][j + 1])- dungeon[i][j], 1)

代码:

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        int m = dungeon.length;
        int n = dungeon[0].length;
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 0; i < m + 1 ;i ++) {
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        }

        dp[m][n - 1] = 1;
        dp[m - 1][n] = 1;
        for (int i = m - 1; i >= 0 ; i --) {
            for (int j = n - 1; j >= 0; j --) {
                int temp = Math.min(dp[i + 1][j], dp[i][j + 1]);
                dp[i][j] = Math.max(temp - dungeon[i][j], 1);
            }
        }
        return dp[0][0];
    }
}

回溯超时代码:

class Solution {
    private int res = Integer.MAX_VALUE;
    public int calculateMinimumHP(int[][] dungeon) {
        List<Integer> path = new ArrayList<>();
        backtrack(dungeon, dungeon.length, dungeon[0].length, 0, 0, path);
        return res;
    }
    public void backtrack(int[][] dungeon, int m, int n, int i, int j, List<Integer> path) {
        if (i == m - 1 && j == n - 1) {
            path.add(dungeon[i][j]);
            res = Math.min(res, getMin(path));
            path.remove(path.size() - 1);
            return;
        }
        path.add(dungeon[i][j]);
        if (i + 1 < m) {
            backtrack(dungeon, m, n, i + 1, j, path);
        }
        if (j + 1 < n) {
            backtrack(dungeon, m, n, i, j + 1, path);
        }
        path.remove(path.size() - 1);
    }
    public int getMin(List<Integer> path) {
        int min = 1;
        int left = 1;
        for (int num : path) {
            left -= num;
            min = Math.max(min, left);
        }
        return min;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值