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

68 阅读3分钟

问题描述

小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 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。我们的目标是最大化这个得分。这里采用动态规划思想解题。解题过程如下:

  1. 理解得分计算

    • 得分由两部分组成:两个景点的评分之和 values[i] + values[j],以及它们下标差的相反数 i - j
    • 由于 i < ji - j 总是负数,所以我们实际上是在最小化 j - i
  2. 动态规划状态定义

    • 定义 dp[i] 为考虑前 i 个景点,以第 i 个景点结尾时的最大得分。
  3. 状态转移方程

    • 对于每个景点 i,我们有两种选择:不选择它,或者选择它。
    • 如果不选择第 i 个景点,那么最大得分就是 dp[i-1]
    • 如果选择第 i 个景点,我们需要找到之前的最佳景点 kk < i),使得 dp[k] + values[i] + k - i 最大。
  4. 优化

    • 由于 k - i 是负数,我们实际上希望 k 尽可能小,这样 k - i 的绝对值就尽可能大。
    • 因此,我们只需要维护一个变量 max_score 来记录到目前为止的最大得分,每次更新 dp[i] 时,我们比较 max_score 和当前的得分,取较大值。
  5. 实现

    • 初始化 dp[0]values[0],因为只有一个景点时,最大得分就是其自身的评分。
    • 遍历每个景点 i,更新 dp[i]max_score
    • dp[i] 的值是 values[i] + idp[i-1] 中的较大值,因为我们需要最大化当前景点的得分。
    • max_score 的值是 dp[i-1] + values[i] - i 和当前 max_score 中的较大值,因为我们需要最大化两个景点的组合得分。
  6. 返回结果

    • 遍历结束后,max_score 就是全局最大得分。

这种方法的优点是时间复杂度较低,只需要 O(n) 的时间,空间复杂度也较低,只需要 O(n) 的空间。它利用了问题的特定性质,通过维护一个当前最大得分的变量来避免复杂的状态转移,从而简化了问题。

代码实现

def solution(values: list) -> int:
     n = len(values)
    if n < 2:   # 景区数小于2,则得分为0
        return 0

    # 初始化dp数组,dp[i]表示以第i个景点结尾的最大得分
    dp = [0] * n
    dp[0] = values[0]
    max_score = float('-inf')  # 初始化最大得分为负无穷

    for i in range(1, n):
        # 计算以第i个景点结尾的最大得分
        dp[i] = max(dp[i-1], values[i] + i)
        # 更新全局最大得分
        max_score = max(max_score, dp[i-1] + values[i] - i)

    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)
    

上述代码的时间复杂度和空间复杂度均为O(n)