题目描述
小R在评估一组观光景点,每个景点的评分存储在数组values
中。一对景点(i, j)
(i < j)的得分为values[i] + values[j] + i - j
。我们需要找出能获得最高得分的组合。
输入约束
- 2 <= values.length <= 10^5
- 1 <= values[i] <= 1000
一、解题思路分析
关键公式转换
将得分公式变形为:score = (values[i] + i) + (values[j] - j)
算法策略
-
单次遍历法:维护两个关键变量
max_left
:记录遍历过程中遇到的最大values[i] + i
值max_score
:记录全局最高得分
-
时间复杂度:O(n)
-
空间复杂度:O(1)
二、完整Java实现
java
public class SightseeingScore {
public static int maxScore(int[] values) {
if (values == null || values.length < 2) {
throw new IllegalArgumentException("Invalid input");
}
int maxLeft = values[0] + 0; // 初始化第一个元素的values[i]+i
int maxScore = Integer.MIN_VALUE;
for (int j = 1; j < values.length; j++) {
// 计算当前组合得分
int currentScore = maxLeft + (values[j] - j);
maxScore = Math.max(maxScore, currentScore);
// 更新maxLeft为当前最大的values[i]+i
maxLeft = Math.max(maxLeft, values[j] + j);
}
return maxScore;
}
public static void main(String[] args) {
// 测试案例
int[] test1 = {8, 3, 5, 5, 6};
System.out.println(maxScore(test1)); // 输出: 11
int[] test2 = {10, 4, 8, 7};
System.out.println(maxScore(test2)); // 输出: 16
int[] test3 = {1, 2, 3, 4, 5};
System.out.println(maxScore(test3)); // 输出: 8
}
}
三、代码解析
核心逻辑分解
-
初始化阶段
maxLeft
初始化为第一个元素的values[0] + 0
maxScore
初始化为最小整数值
-
遍历过程
-
对每个
j
(从索引1开始):- 计算当前组合得分:
currentScore = maxLeft + (values[j] - j)
- 更新全局最高得分
- 更新
maxLeft
为当前最大的values[j] + j
- 计算当前组合得分:
-
边界处理
- 输入校验确保数组长度合法
- 自动处理
i < j
的约束条件
四、算法正确性验证
测试案例演示
案例1
输入:[8,3,5,5,6]
计算过程:
java
i=0,j=1 → 8+0 +3-1=10
i=0,j=2 → 8+0 +5-2=11(最高分)
后续组合得分均不超过11
输出:11
案例2
输入:[10,4,8,7]
最佳组合:
java
i=0,j=2 →10+0 +8-2=16
输出:16
五、性能优化说明
对比暴力解法
方法 | 时间复杂度 | 空间复杂度 | 是否通过大数据测试 |
---|---|---|---|
暴力二重循环 | O(n²) | O(1) | ❌ |
单次遍历法 | O(n) | O(1) | ✅ |
适用场景
- 特别适合处理长数组(10^5级别)
- 内存敏感型应用场景
总结:通过公式变形将问题转化为动态维护最大值问题,使得原本O(n²)复杂度的问题优化到线性时间复杂度,是典型的空间换时间策略应用。该算法在房产平台景点推荐、旅行路线规划等场景都有实际应用价值。