观光景点组合得分问题分析与解题思路
问题理解
给定一个数组values,其中values[i]表示第i个观光景点的评分。我们定义景点之间的距离为它们的下标差j - i,并且一对景点(i < j)的观光组合得分公式为:
css
复制代码
得分 = values[i] + values[j] + (i - j)
目标是找到两景点(i, j),使得得分达到最大值。
得分公式解析
得分公式可以拆解为两部分:
- 评分部分:
values[i] + values[j] - 距离部分:
i - j
根据这个公式,我们可以重新表达为:
css
复制代码
得分 = (values[i] - i) + (values[j] + j)
其中,values[i] - i和values[j] + j是两个独立的部分。这个公式告诉我们:要最大化得分,我们可以分别找到values[i] - i和values[j] + j的最大值,并组合它们。
优化思路
根据上述分析,我们可以采取以下步骤:
- 遍历所有可能的
i,计算values[i] - i。 - 对于每个
j(j > i),计算values[j] + j。 - 对于每个
j,使用values[i] - i的最大值(从之前的i中获取),并加上values[j] + j,计算得分。
这样,我们就能够在遍历过程中实时更新最大得分,而无需使用两层嵌套循环来检查每一对(i, j)。
时间复杂度分析
通过上述优化方法,我们将问题的时间复杂度降低为O(N),其中N是数组values的长度。这样,计算每个j对应的最大得分时,我们只需要一次遍历即可。
代码实现
java
复制代码
public class Main {
public static int solution(int[] values) {
if (values == null || values.length < 2) {
return 0; // 如果数组为空或只有一个元素,无法形成有效的组合
}
int maxScore = Integer.MIN_VALUE; // 初始化最大得分
int maxValue = values[0] - 0; // 初始时,maxValue等于第一个元素的值减去下标0
// 从第二个元素开始遍历
for (int j = 1; j < values.length; j++) {
// 计算当前得分
int currentScore = values[j] + j + maxValue;
// 更新最高得分
maxScore = Math.max(maxScore, currentScore);
// 更新 maxValue,使得它始终保存前面所有元素的最大值 (values[i] - i)
maxValue = Math.max(maxValue, 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); // 11
System.out.println(solution(new int[]{10, 4, 8, 7}) == 16 ? 1 : 0); // 16
System.out.println(solution(new int[]{1, 2, 3, 4, 5}) == 8 ? 1 : 0); // 8
}
}
解题过程
-
初始化:
maxScore:用于存储当前找到的最大得分,初始值为Integer.MIN_VALUE。maxValue:用于存储前面所有values[i] - i中的最大值,初始值为values[0] - 0。
-
遍历:
- 对于每个
j(j > i),计算当前得分:currentScore = values[j] + j + maxValue,其中maxValue是i位置之前的最大值values[i] - i。 - 更新
maxScore为当前得分与之前得分的最大值。 - 更新
maxValue为values[j] - j和之前maxValue的较大值,以确保在下次计算时能够使用最大的values[i] - i。
- 对于每个
-
返回最大得分:
- 遍历结束后,
maxScore保存的是我们找到的最大得分。
- 遍历结束后,
测试样例验证
-
输入:
values = [8, 3, 5, 5, 6]- 输出:
11 - 解析:最大得分发生在i=0, j=4时,得分为
8 + 6 + (0 - 4) = 11。
- 输出:
-
输入:
values = [10, 4, 8, 7]- 输出:
16 - 解析:最大得分发生在i=0, j=2时,得分为
10 + 8 + (0 - 2) = 16。
- 输出:
-
输入:
values = [1, 2, 3, 4, 5]- 输出:
8 - 解析:最大得分发生在i=0, j=4时,得分为
1 + 5 + (0 - 4) = 8。
- 输出:
总结
通过优化,我们将时间复杂度从O(N^2)降低到了O(N),大大提高了效率。在处理较大规模的输入时,这种优化将显著减少计算时间。我们通过维护一个单一的maxValue来避免内层循环的冗余计算,从而提升了程序的执行效率。