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

81 阅读6分钟

一、题目分析

本题围绕观光景点展开,每个景点都具备一个评分,这些评分存放在数组 values 中,其中 values[i] 代表第 i 个观光景点的评分。同时,定义了景点之间的距离是由它们下标的差值(j - i)来体现。而对于一对观光景点(需满足 i < j),其观光组合得分有特定的计算公式:values[i] + values[j] + i - j,也就是两个景点的评分之和减去它们之间的距离。我们的核心任务就是要找出在所有可能的景点组合当中,哪一种组合能够获得最高的得分。

二、解题思路探讨

要解决这个问题,可以从以下几个关键思路入手:

  1. 暴力解法(穷举所有组合)思路分析 最直观的想法就是通过两层嵌套的循环,去遍历所有可能的景点组合情况,然后按照给定的得分计算公式计算每一对景点组合的得分,并在过程中记录下出现的最高得分。例如,外层循环控制选择第一个景点(索引为 i),内层循环从 i + 1 开始遍历后面的景点(索引为 j),对于每一对 (i, j) 计算其观光组合得分 values[i] + values[j] + i - j,然后与已记录的最高得分比较,若大于最高得分则更新最高得分记录。 然而,这种暴力解法的时间复杂度是 O(n2)O(n^2)n 为景点个数,因为有两层循环,每层都与 n 相关),当景点数量较多时,计算量会迅速增大,效率较低,所以我们需要寻找更优化的解题思路。
  2. 优化思路(类似动态规划或贪心思想)分析 仔细观察组合得分的计算公式 values[i] + values[j] + i - j,可以将其变形为 (values[i] + i) + (values[j] - j)。从这个变形后的式子中我们可以发现,对于某个景点 j,要使其与前面的景点 i 组成的组合得分最高,其实就是要找到前面景点中 values[i] + i 的最大值,因为 values[j] - j 这部分是由当前景点 j 本身决定的固定值。 基于这样的思路,我们可以通过一次遍历数组来解决问题。在遍历过程中,动态地记录下从第一个景点开始到当前遍历位置左侧,所能得到的 values[i] + i 的最大值(设为 max_value),然后对于当前正在遍历的景点 j,计算它与左侧这个最大值对应的景点组成的组合得分(即 max_value + values[j] - j),并在遍历过程中不断比较和更新记录最高得分(设为 max_score)。

三、具体解题步骤

以下是按照上述优化思路详细展开的解题步骤:

  1. 初始化相关变量 - 定义一个变量 max_score,用于记录在遍历过程中找到的观光景点组合的最高得分,初始时可先将其设为第一个景点的组合得分情况(也就是 values[0] + 0,因为第一个景点不存在左侧与之组合的其他景点了),即 max_score = values[0] + 0
  2. 开始遍历景点数组(从第二个景点开始) - 对于数组 values 中的每个景点(从索引 1 开始到 len(values) - 1): - 首先,计算当前景点左侧能提供的最大 values[i] + i 的值(记为 max_value),在遍历过程中我们动态维护这个最大值,每到一个新景点都比较更新它。 - 然后,根据优化思路中的得分计算公式变形,计算当前景点与左侧具有最大 max_value 的景点组成的观光组合得分,计算公式为 current_score = max_value + values[i] - i。 - 接着,将当前计算得到的 current_score 和已记录的最高得分 max_score 进行比较,若 current_score 大于 max_score,则更新 max_score 的值为 current_score,即 max_score = max(max_score, current_score),确保 max_score 始终记录的是当前找到的最高得分情况。 - 最后,更新 max_value,将其设置为当前景点的 values[i] + i 和之前 max_value 的较大值,即 max_value = max(max_value, values[i] + i),为后续遍历的景点计算组合得分做准备,保证 max_value 始终反映的是已遍历景点中能提供的最大相关值。
  3. 完成遍历,返回结果 当遍历完整个 values 数组后,此时 max_score 中记录的值就是所有可能的观光景点组合中的最高得分,直接返回 max_score 即可。
def solution(values: list) -> int:
      # 初始化 max_score 为第一个景点的评分加上其索引
        max_score = values[0] + 0  # values[0] + i, 当 i = 0
        ans = 0  # 初始化最终结果为0
        
        # 从第二个景点开始遍历
        for i in range(1, len(values)):
            # 计算当前观光组合的得分,即当前景点的评分 + 左侧景点的评分 - 两者之间的距离
            current_score = max_score + values[i] - i
            # 更新最终结果为当前得分和之前结果的较大值
            ans = max(ans, current_score)
            # 更新 max_score 为当前景点的评分 + 其在数组中的索引,因为对于之后的任意景点 k(k > i),values[i] + i 将会是与 values[k] 组合时可能得到的最大 values[i] + i
            max_score = max(max_score, values[i] + i)
        
        # 返回最终结果
        return ans

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)

四、复杂度分析

  1. 时间复杂度: 整个解题过程主要依赖于对景点数组 values 的一次遍历操作,循环次数与景点个数 n 相等,而在每次循环内进行的操作主要是数值的比较、简单计算以及变量更新,这些操作的时间复杂度都是常数级别,所以整体的时间复杂度为 O(n)O(n),相较于暴力解法的 O(n2)O(n^2) 效率有了显著提升,能够更快速地处理包含较多景点数量的情况。
  2. 空间复杂度: 在整个解题过程中,只额外使用了几个固定的变量(如 max_scoremax_value 等)来辅助计算,这些变量所占用的空间大小不会随着景点个数 n 的增加而变化,始终保持在常数级别,所以空间复杂度为 O(1)O(1),意味着算法在空间使用方面较为节省,不会因输入规模增大而占用过多内存空间。