一、题目分析
本题围绕观光景点展开,每个景点都具备一个评分,这些评分存放在数组 values 中,其中 values[i] 代表第 i 个观光景点的评分。同时,定义了景点之间的距离是由它们下标的差值(j - i)来体现。而对于一对观光景点(需满足 i < j),其观光组合得分有特定的计算公式:values[i] + values[j] + i - j,也就是两个景点的评分之和减去它们之间的距离。我们的核心任务就是要找出在所有可能的景点组合当中,哪一种组合能够获得最高的得分。
二、解题思路探讨
要解决这个问题,可以从以下几个关键思路入手:
- 暴力解法(穷举所有组合)思路分析 最直观的想法就是通过两层嵌套的循环,去遍历所有可能的景点组合情况,然后按照给定的得分计算公式计算每一对景点组合的得分,并在过程中记录下出现的最高得分。例如,外层循环控制选择第一个景点(索引为
i),内层循环从i + 1开始遍历后面的景点(索引为j),对于每一对(i, j)计算其观光组合得分values[i] + values[j] + i - j,然后与已记录的最高得分比较,若大于最高得分则更新最高得分记录。 然而,这种暴力解法的时间复杂度是 (n为景点个数,因为有两层循环,每层都与n相关),当景点数量较多时,计算量会迅速增大,效率较低,所以我们需要寻找更优化的解题思路。 - 优化思路(类似动态规划或贪心思想)分析 仔细观察组合得分的计算公式
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)。
三、具体解题步骤
以下是按照上述优化思路详细展开的解题步骤:
- 初始化相关变量 - 定义一个变量
max_score,用于记录在遍历过程中找到的观光景点组合的最高得分,初始时可先将其设为第一个景点的组合得分情况(也就是values[0] + 0,因为第一个景点不存在左侧与之组合的其他景点了),即max_score = values[0] + 0。 - 开始遍历景点数组(从第二个景点开始) - 对于数组
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始终反映的是已遍历景点中能提供的最大相关值。 - 完成遍历,返回结果 当遍历完整个
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)
四、复杂度分析
- 时间复杂度: 整个解题过程主要依赖于对景点数组
values的一次遍历操作,循环次数与景点个数n相等,而在每次循环内进行的操作主要是数值的比较、简单计算以及变量更新,这些操作的时间复杂度都是常数级别,所以整体的时间复杂度为 ,相较于暴力解法的 效率有了显著提升,能够更快速地处理包含较多景点数量的情况。 - 空间复杂度: 在整个解题过程中,只额外使用了几个固定的变量(如
max_score、max_value等)来辅助计算,这些变量所占用的空间大小不会随着景点个数n的增加而变化,始终保持在常数级别,所以空间复杂度为 ,意味着算法在空间使用方面较为节省,不会因输入规模增大而占用过多内存空间。