动态规划(二)| 豆包MarsCode AI刷题

44 阅读3分钟

前情提要

按照上一篇我们说的,动态规划主要有三大要素:

  • 建立dp体现题目信息
  • 建立合适的转移方程
  • 定义初始状态

但又这样一种情况,我们往往不会建立dp数组而是通过循环来更新要求的最大/最小值。

题目示例

  • 小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。一对景点 (i < j) 的观光组合得分为 values[i] + values[j] + i - j,也就是两者评分之和减去它们之间的距离。小R想知道,在哪种情况下能够获得观光景点组合的最高得分。
  • 小S拿到了一个长度为 nn 的环形数组,并定义了两个下标 ii 和 jj 的贡献值公式为:
    f(i, j) = (a_i + a_j) × dist(i, j),其中 dist(i, j) 是下标 ii 和 jj 在数组中的最短距离。小S希望找到一对下标,使得它们的贡献值尽可能大。环形数组的特点是最左和最右的元素也是相邻的。你需要帮助她找到最大贡献值。

这两题比较像我们就一起讲啦!

题目讲解

这样的题目中,我们比较关心的是下标的变动,因为取值非常好取。那下标的变动组合该如何有条理的表示呢,我们手动来做的话,往往是从1打头开始,1到2,1到3,......,再换2到头,直到循环完毕,那么i每从一个数字打头,为了不走回头路,j实际上都是从i+1开始。由此在代码中,我们可以用循环嵌套来表示。

而对于环形数组,需要注意的是,此时计算距离不是简单的下标相减,而是要考虑环形数组两个方向上距离更短的情况。

最后关于我们要求的最大贡献值/最高得分,我们只需要定义一个max_value变量来储存,每次只需要使用max函数来对计算的结果取大更新就可以了,而不需要建立一整个dp数组来进行储存。

题目解答

def solution(n: int, nums: list) -> int:
    max_contrib = 0
    for i in range(n):
        for j in range(i + 1, n):
            # 计算距离
            dist_ij = min(j - i, n - (j - i))
            contrib_ij = (nums[i] + nums[j]) * dist_ij
            max_contrib = max(max_contrib, contrib_ij)            
    return max_contrib

扩展思考

对于环形数组,在计算距离的时候,除了使用min来找出两个方向上的最近距离,还有什么办法呢。 还有一个老办法就是,扩展我们的环形数组,在原来的基础上,后面再加上第1个位置到倒数第二个位置的数据列表,这样“正着”看的距离也是对的。

感兴趣的朋友可以按这个方向再试试吧!