LeetCode 174困难动态规划
地下城游戏 图解题解
这道题到底在问什么
table.dungeon, .dungeon th, .dungeon td { border:3px solid black; } .dungeon th, .dungeon td { text-align: center; height: 70px; width: 70px; } 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。
- dungeon
- [[-2,-3,3],[-5,-10,1],[10,30,-5]]
- 输出
- 7
先想最直接的笨办法
DP 表跟着代码走:推进语句是:dp[m - 1][n] = 1。处理过的部分不再重新枚举。(动画第 10 步)
最优解:一步一步想明白
- 3下面 9 步动画会按主解代码推进,而不是泛泛讲题型。
- 4先读清 地下城游戏 的输入输出DP 表跟着代码走:先把示例输入映射到代码参数:def calculateMinimumHP(self, dungeon):。
- 5m = len(dungeon);n = len(dungeon[0]);dp = [[float('inf')] * (n + 1) for _ in range(m + 1)]DP 表跟着代码走:开局只立住必要变量:m = len(dungeon);n = len(dungeon[0]);dp = [[float('inf')] * (n + 1) for _ in range(m + 1)]。
- 6for r in range(m - 1, -1, -1):DP 表跟着代码走:主流程从这里开始:for r in range(m - 1, -1, -1):。
- 7根据题意分情况DP 表跟着代码走:题目条件落到这一行:满足条件就进入对应分支。
- 8return dp[0][0]DP 表跟着代码走:对应代码:return dp[0][0]。这一行决定当前轮对答案有什么贡献。
- 9从终点倒推最低需求DP 表跟着代码走:边界跟着代码看:dp[m][n - 1] = 1。
- 10dp[m - 1][n] = 1DP 表跟着代码走:推进语句是:dp[m - 1][n] = 1。处理过的部分不再重新枚举。
- 11return dp[0][0]DP 表跟着代码走:到这里,dp 已经能表达题目要求。
- 12return:return dp[0][0]DP 表跟着代码走:最后检查返回形态:返回值、原地修改或设计类状态,要和 LeetCode 判题方式一致。
- 15记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
⚠️ 容易写错的地方
✗ 错:从起点正推剩余血量
✓ 对:从终点倒推最低需求
正推需要同时考虑路径和最低值
✗ 错:血量允许为 0
✓ 对:至少为 1
骑士血量必须始终为正
完整代码(Python)
Python
class Solution:
def calculateMinimumHP(self, dungeon):
m = len(dungeon)
n = len(dungeon[0])
dp = [[float('inf')] * (n + 1) for _ in range(m + 1)]
dp[m][n - 1] = 1
dp[m - 1][n] = 1
for r in range(m - 1, -1, -1):
for c in range(n - 1, -1, -1):
need = min(dp[r + 1][c], dp[r][c + 1]) - dungeon[r][c]
dp[r][c] = max(1, need)
return dp[0][0]复杂度
时间复杂度
O(mn)
每个格子计算一次
空间复杂度
O(mn)
dp 表
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 地下城游戏 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「动态规划」,换最直接的暴力解会差在哪?+
动态规划抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。