问题描述
小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
问题解析
我们需要找到一个具有最大得分的景点组合,其中得分的计算方式为:
score=values[i]+values[j]+(i−j) =values[i]+values[j]+(i−j)
其中 i 和 j 是两个不同的景点下标,且 i<j 。这意味着我们需要在一对景点之间找到最大得分。
观察与优化
从问题的定义可以看出,我们的目标是最大化这个得分公式:
score=values[i]+values[j]+(i−j)\text{score} = \text{values}[i] + \text{values}[j] + (i - j)score=values[i]+values[j]+(i−j)
我们可以将其拆解成两部分:
- 第一部分:values[i]−i\text{values}[i] - ivalues[i]−i
- 第二部分:values[j]+j\text{values}[j] + jvalues[j]+j
这意味着,公式可以变为:
score=(values[i]−i)+(values[j]+j)\text{score} = (\text{values}[i] - i) + (\text{values}[j] + j)score=(values[i]−i)+(values[j]+j)
优化思路
我们可以在遍历过程中维护两个值:
- max1=values[i]−i\text{max1} = \text{values}[i] - imax1=values[i]−i(第一个景点的得分值)
- max2=values[j]+j\text{max2} = \text{values}[j] + jmax2=values[j]+j(第二个景点的得分值)
每次计算时,只需要找到目前 max1\text{max1}max1 的最大值和 max2\text{max2}max2 的值的和。这样可以避免我们原本的两层嵌套循环,从而大大提升效率。
算法设计
- 初始化:维护
max1为一个非常小的值(代表第一个景点的得分最大值),max2为当前景点的值加上其下标。 - 遍历数组:从第一个景点到最后一个景点,依次计算每个景点的得分,并更新
max1和max2。 - 返回结果:最终返回最大得分。
代码实现
#include <vector>
#include <iostream>
#include <climits> // 为了使用INT_MIN
using namespace std;
int solution(vector<int>& values) {
int maxScore = INT_MIN; // 用于存储最终的最大得分
int max1 = INT_MIN; // 用于存储 values[i] - i 的最大值
// 从第二个元素开始计算最大得分
for (int j = 1; j < values.size(); ++j) {
// 计算当前组合的得分
maxScore = max(maxScore, max1 + values[j] + j);
// 更新 max1 为当前 values[i] - i 的最大值
max1 = max(max1, values[j - 1] - (j - 1));
}
return maxScore;
}
int main() {
// 测试样例
cout << solution({8, 3, 5, 5, 6}) << endl; // 输出: 11
cout << (solution({8, 3, 5, 5, 6}) == 11) << endl;
cout << (solution({10, 4, 8, 7}) == 16) << endl;
cout << (solution({1, 2, 3, 4, 5}) == 8) << endl;
return 0;
}
代码解析
-
初始化变量:
maxScore用于记录计算过程中的最大得分,初始化为INT_MIN,表示尚未计算任何得分。max1用于存储values[i] - i的最大值,初始化为INT_MIN。
-
遍历计算:
- 从第二个元素开始遍历(即
j = 1),因为i和j必须满足i < j。 - 每次计算当前景点
j与之前景点i的得分,更新maxScore。 - 更新
max1,保持其为values[i] - i的最大值。
- 从第二个元素开始遍历(即
-
返回结果:
- 最后,返回存储的最大得分
maxScore。
- 最后,返回存储的最大得分
时间复杂度
- 该算法仅需要一次遍历整个数组,所以时间复杂度为 O(n) ,其中
n是values数组的长度。
空间复杂度
- 由于只使用了常数级的额外空间,空间复杂度为 O(1) 。