312. 戳气球
375. 猜数字大小 II
方法一:递归
猜的数字是 k,而答案不是 k 的话,问题变为求解 (1, k - 1) 和 (k + 1, n) 的子问题需要的代价的最大值。
class Solution:
def getMoneyAmount(self, n: int) -> int:
@lru_cache(None)
def dfs(start, end):
if start >= end: return 0
# if memo[start][end]: return memo[start][end]
res = inf
for k in range(start, end + 1):
res = min(res, max(dfs(start, k - 1), dfs(k + 1, end)) + k)
# memo[start][end] = res
return res
# return min(max(dfs(x, k - 1), dfs(k + 1, y)) + k for k in range(x, y + 1)) if y > x else 0
# memo = [[0] * (n + 1) for _ in range(n + 1)]
return dfs(1, n)
方法二:动态规划
1、定义: f(i, j) 表示在范围 [i, j] 内确保获胜的最小现金数,目标是计算 f(1, n)。
2、边界: 当 i ≥ j 时,f(i, j) = 0。
3、状态转移方程:
4、逆向遍历: 计算子问题的顺序为先计算规模小的子问题,后计算规模大的子问题。
class Solution:
def getMoneyAmount(self, n: int) -> int:
f = [[0] * (n + 1) for _ in range(n + 1)]
for i in range(n - 1, 0, -1):
for j in range(i + 1, n + 1):
f[i][j] = min(k + max(f[i][k - 1], f[k + 1][j]) for k in range(i, j))
return f[1][n]