AI刷题-观光景点组合得分问题 | 豆包MarsCode AI刷题

94 阅读3分钟

题目解析

题目

小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 value 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j-i表示一对景点 (i<j) 的观光组合得分为 values[i] + values[j] + i - j ,也就是两者评分之和减去它们之间的距离。小R想知道,在哪种情况下能够获得观光景点组合的最高得分。

测试用例

样例1:

输入:values = [8, 3, 5, 5, 6]
输出:11

样例2:

输入:values = [10, 4, 8, 7]
输出:16

样例3:

输入:values = [1, 2, 3, 4, 5]
输出:8

具体解法

剖析

题目的关键点在于values[i] + values[j] + i - j的求解

我们把公式拆解为两部分:

  • values[i] + i 是关于第一个景点 i 的信息;

  • values[j] - j 是关于第二个景点 j 的信息。 这样,我们的目标就是在 i < j 的情况下,找到最大的 values[i] + i + values[j] - j

解法思路

我们可以遍历数组 values,对于每一个 j 值,我们去寻找在 j 之前的所有 i 的最大值 values[i] + i

记录遍历过程中最大的 values[i] + i 的值,用它和当前的 values[j] - j 相加,得到最大可能的得分。

更新遍历中的最大得分,最终得到结果。

代码实现

定义max_score用于记录最大得分

max_score = 0

初始化 values[i] + i 最大值为第一个景点的值加上它的索引

max_i_value = values[0] + 0 

遍历元素,更新最大值 从第二个元素开始遍历

for j in range(1, len(values)):
        max_score = max(max_score, max_i_value + values[j] - j)
        max_i_value = max(max_i_value, values[j] + j)

循环结束返回最大得分

return max_score

注意事项

在 for循环中,要先更新 max_score 而不是 max_i_value 因为我们希望在计算得分时使用的 max_i_value 是从 j 的前一个位置及之前的位置中得到的最大值,而不是当前 j 位置的值。即要满足题中i<j的条件

知识总结

该题目综合运用了动态规划的状态更新、前缀和的优化思路、贪心算法的当前最优选择以及动态最大值的维护等知识。

我们引入了 max_i_value,表示 values[i] + ij 之前位置的最大值,这样对于每个 j,可以在常数时间内得出 i < j 的前缀最大值,而无需重新遍历之前的元素。

在每次遍历时,我们更新 max_score,确保每一步都保持当前的最优解。 这是贪心思想的体现,在动态增长的过程中始终选择当前最优状态,从而在遍历结束时得到全局最优解

代码

def solution(values: list) -> int:
    max_score = 0
    max_i_value = values[0] + 0  # 初始化最大值为第一个景点的值加上它的索引

    # 从第二个元素开始遍历
    for j in range(1, len(values)):
        # 计算得分
        max_score = max(max_score, max_i_value + values[j] - j)
        
        # 更新 max_i_value 为前 j 个景点的最大值
        max_i_value = max(max_i_value, values[j] + j)

    return max_score
if __name__ == '__main__':
    print(solution(values=[8, 3, 5, 5, 6]) == 11)
    print(solution(values=[10, 4, 8, 7]) == 16)
    print(solution(values=[1, 2, 3, 4, 5]) == 8)