一,题目详情
1,问题描述
小R正在研究一组观光景点,每个景点都有一个评分,保存在数组 values 中,其中 values[i] 表示第 i 个观光景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。
一对景点 (i < j) 的观光组合得分为 values[i] + values[j] + i - j,也就是两者评分之和减去它们之间的距离。
小R想知道,在哪种情况下能够获得观光景点组合的最高得分。
2,测试样例
样例1:
输入:
values = [8, 3, 5, 5, 6]
输出:
11
解释:最高得分的组合是 (0, 4),得分为 8 + 6 + 0 - 4 = 11。
样例2:
输入:
values = [10, 4, 8, 7]
输出:
16
解释:最高得分的组合是 (0, 2),得分为 10 + 8 + 0 - 2 = 16。
样例3:
输入:
values = [1, 2, 3, 4, 5]
输出:
8
解释:最高得分的组合是 (3, 4),得分为 4 + 5 + 3 - 4 = 8。
3,约束条件
- 2 ≤ values.length ≤ 1000
- 1 ≤ values[i] ≤ 1000
二,解题思路
1,问题分析
我们需要找到一对景点 (i < j),使得 values[i] + values[j] + i - j 最大。这个表达式可以重新排列为 (values[i] + i) + (values[j] - j)。因此,对于每个 j,我们需要找到前面所有 i 中 values[i] + i 的最大值,然后与 values[j] - j 相加,得到当前 j 的最大得分。
2,算法策略
我们可以使用动态规划的思想来解决这个问题:
- 初始化一个变量 max_so_far 来记录 values[i] + i 的最大值。
- 遍历数组,对于每个 j,计算当前 j 的 values[j] - j,并与 max_so_far 相加得到当前得分。
- 更新 max_so_far 为当前 j 的 values[j] + j 和 max_so_far 中的较大值。
- 在遍历过程中,记录所有得分中的最大值。
3,逐步推演(以样例1为例)
输入 values = [8, 3, 5, 5, 6]
,推演过程如下:
步骤 | j | values[j] | values[j] - j | max_so_far | current_score | max_score |
---|---|---|---|---|---|---|
初始 | - | - | - | 8 + 0 = 8 | - | -∞ |
1 | 1 | 3 | 3 - 1 = 2 | 8 | 8 + 2 = 10 | 10 |
2 | 2 | 5 | 5 - 2 = 3 | 8 | 8 + 3 = 11 | 11 |
3 | 3 | 5 | 5 - 3 = 2 | 8 | 8 + 2 = 10 | 11 |
4 | 4 | 6 | 6 - 4 = 2 | 8 | 8 + 2 = 10 | 11 |
最终结果 max_score = 11
,与预期一致。
三,代码实现
Python复制
ini
def solution(values: list) -> int:
if len(values) < 2:
return 0 # 根据约束条件,这行可能不会执行
max_so_far = values[0] + 0
max_score = float('-inf')
for j in range(1, len(values)):
current_score = max_so_far + (values[j] - j)
if current_score > max_score:
max_score = current_score
# 更新max_so_far为当前j作为i时的最大值
current_i_value = values[j] + j
if current_i_value > max_so_far:
max_so_far = current_i_value
return max_score
1,复杂度分析
-
时间复杂度:O(n)
- 只需一次线性遍历(n为数组长度)
-
空间复杂度:O(1)
- 仅使用常数级额外空间
2,边界测试
Python复制
ini
if __name__ == '__main__':
# 常规测试
print(solution([8, 3, 5, 5, 6]) == 11)
print(solution([10, 4, 8, 7]) == 16)
print(solution([1, 2, 3, 4, 5]) == 8)
# 边界测试:数组长度为2
print(solution([1, 2]) == 2)
# 边界测试:所有元素相同
print(solution([5, 5, 5, 5]) == 5 + 5 + 0 - 1 = 9)
四,总结
通过将问题转化为动态规划的形式,我们实现了:
- 线性时间复杂度:一次遍历解决问题
- 常数空间复杂度:无需额外存储空间
- 普适性:适用于所有整数数组
这种解法不仅高效,还展现了动态规划在算法中的巧妙应用。当遇到"需要在数组中找到最优组合"类问题时,动态规划往往是解决问题的关键钥匙。