第三题思路
计算存储二维前缀和,二维前缀和与概率论中概率分布函数的计算类似。有了前缀和之后对应矩形的面积计算复杂度为常数级与矩形边长无关。
注意边界处理即可。
第四题(602金银珠宝的数值)
思路
典型的区间DP
代码
def solution(stones, c):
n = len(stones)
m = len(c)
# dp[i][j] 表示从stones[i]到stones[j]的区间获得最大财富
dp = [[float('-inf')] * n for _ in range(n)]
# 初始化边界
for i in range(n-1-(n-m+1)+1+1):
dp[i][i+n-m] = max(stones[i]*c[-1], stones[i+n-m]*c[-1])
# 动态规划填表
for ki, length in enumerate(range(n-m+2, n + 1), start=2): # length表示当前考虑的全闭区间长度
for i in range(n - length+1):
j = i + length - 1
k = m - ki
if i > j:
break
# 选择顶部的珠宝
dp[i][j] = max(dp[i][j], stones[i] * c[k] + (dp[i + 1][j] if i + 1 <= j else 0))
# 选择底部的珠宝
dp[i][j] = max(dp[i][j], stones[j] * c[k] + (dp[i][j - 1] if i <= j - 1 else 0))
# 返回从0到n-1区间的最大财富
return dp[0][n - 1]
注意
- 初始化边界
- 状态转移边界
- 区间此处我选择的是全闭,注意取值边界与意义
官方题解
官方给出的是依据符文序列的一维DP,给出了一种状态压缩方案。
代码
def solution(stones: list, c: list) -> int:
n, m = len(stones), len(c)
dp = [0] * (m+1)
for i in range(m-1, -1, -1):
prev = dp[i+1]
for left in range(i, -1, -1):
next_val = dp[left]
dp[left] = max(c[i]*stones[left]+prev, c[i]*stones[n-1-i+left]+dp[left])
prev = next_val
return dp[0]
背包的状态压缩有时依赖时间次序,表中有些位置可以用来作为缓冲。 dp[i+1]保存的是轮次结束的值,dp[left]在max函数中的第二项保存的是上一轮的结果,结果是区间dp长度为i-1的结果。时序上不重叠导致dp的空间压缩。