问题描述
小R正在研究一组观光景点,每个景点有一个评分,存储在数组 values 中,values[i] 表示第 i 个景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。
对于任意一对景点 (i < j),它们的观光组合得分计算方式为:
得分 = values[i] + values[j] + (i - j)
即,两景点的评分之和减去它们之间的距离。
小R的目标是找出在哪种情况下能够获得观光景点组合的最高得分。
思路分析
首先,问题的关键是理解观光组合得分的计算公式:
得分 = values[i] + values[j] + (i - j)
我们可以将这个公式稍微变形为:
得分 = (values[i] + i) + (values[j] - j)
从这里可以看到,对于任意的 i 和 j,我们需要关注的其实是 values[i] + i 和 values[j] - j 的值。
所以,我们可以通过以下方式来优化解法:
-
预处理两个新的数组:
score1[i] = values[i] + i,即每个景点的评分加上其下标。score2[i] = values[i] - i,即每个景点的评分减去其下标。
-
最大化组合得分:
- 要找到一对景点
(i, j),使得score1[i] + score2[j]最大,其中i < j。 - 这意味着,随着
j的增加,我们可以记录到当前的score1的最大值(记为max_score1),然后计算当前的得分max_score1 + score2[j],更新最大得分。
- 要找到一对景点
-
优化思路:
- 对于每个
j,我们可以通过提前计算score1中的最大值来快速求解最优得分,从而减少不必要的计算。
- 对于每个
时间复杂度
- 时间复杂度为 O(n),其中 n 是
values数组的长度。我们只需要一次遍历数组来计算score1和score2,并同时求出最大得分。
Java代码实现
public class Main {
public int solution(int[] values) {
int maxScore = Integer.MIN_VALUE;
int maxScore1 = values[0]; // 初始化为第一个景点的评分加下标
// 遍历数组,计算最大得分
for (int j = 1; j < values.length; j++) {
// 计算当前的得分
int score = maxScore1 + values[j] - j;
// 更新最大得分
maxScore = Math.max(maxScore, score);
// 更新maxScore1(即max(values[i] + i))
maxScore1 = Math.max(maxScore1, values[j] + j);
}
return maxScore;
}
public static void main(String[] args) {
System.out.println(solution(new int[]{8, 3, 5, 5, 6}) == 11 ? 1 : 0);
System.out.println(solution(new int[]{10, 4, 8, 7}) == 16 ? 1 : 0);
System.out.println(solution(new int[]{1, 2, 3, 4, 5}) == 8 ? 1 : 0);
}
}
代码说明
-
初始化:
maxScore用于保存当前的最大得分,初始值为负无穷。maxScore1用于保存到当前位置的values[i] + i的最大值,初始值为第一个景点的评分加上其下标(即values[0] + 0)。
-
遍历数组:
- 从
j = 1开始遍历数组(i会在前面的循环中用到)。 - 对于每一个
j,我们通过maxScore1来获取最大可能的values[i] + i,然后计算当前的得分,并更新最大得分。 - 更新
maxScore1为当前values[j] + j和之前的最大值中的较大者。
- 从
-
输出结果:
- 最后,返回
maxScore,即最优的观光组合得分。
- 最后,返回
测试用例分析
-
样例1:
- 输入:
values = [8, 3, 5, 5, 6] - 输出:
11 - 解释:最优的景点组合是
(i=0, j=3),得分为8 + 5 + 0 - 3 = 11。
- 输入:
-
样例2:
- 输入:
values = [10, 4, 8, 7] - 输出:
16 - 解释:最优的景点组合是
(i=0, j=2),得分为10 + 8 + 0 - 2 = 16。
- 输入:
-
样例3:
- 输入:
values = [1, 2, 3, 4, 5] - 输出:
8 - 解释:最优的景点组合是
(i=0, j=4),得分为1 + 5 + 0 - 4 = 8。
- 输入:
总结
这个问题的关键在于转化计算方式,通过预先计算 values[i] + i 和 values[i] - i,我们能够以线性的时间复杂度完成遍历并获得最优解。通过这种方式,避免了暴力方法中对每对 (i, j) 的遍历,提高了效率。