问题描述
给定一个数组 values,数组中的每个元素表示一个观光景点的评分。景点之间的距离由它们的下标差值 j - i 表示(其中 i 和 j 是景点的下标,且 i < j)。对于一对景点 (i, j),我们定义它们的观光组合得分为:
css
复制代码
得分 = values[i] + values[j] + i - j
其中:
values[i]和values[j]分别是第i个和第j个景点的评分。i - j表示它们之间的下标差。
小R的目标是找到一对景点 (i, j),使得 i < j,并且组合得分最大。
输入与输出
- 输入:一个整数数组
values,其中values[i]表示第i个景点的评分。 - 输出:一个整数,表示能够获得的最大观光组合得分。
示例
样例1:
css
复制代码
输入:values = [8, 3, 5, 5, 6]
输出:11
样例2:
css
复制代码
输入:values = [10, 4, 8, 7]
输出:16
样例3:
css
复制代码
输入:values = [1, 2, 3, 4, 5]
输出:8
思路分析
我们需要最大化表达式:
css
复制代码
得分 = values[i] + values[j] + i - j
其中 i < j。
重写得分公式
将得分公式进行变形,得分为:
css
复制代码
得分 = (values[i] + i) + (values[j] - j)
这意味着:
- 对于
i索引的景点,计算values[i] + i。 - 对于
j索引的景点,计算values[j] - j。
因此,问题转化为:我们要找到一对 i 和 j,使得 i < j 且 values[i] + i 与 values[j] - j 的和最大。
最大化得分
从上面的公式我们可以得出:
- 对于任意一个
j,我们可以计算values[j] - j的值。 - 然后,我们通过遍历所有的
i,计算出values[i] + i的值,尽量寻找最大值。 - 对于每个
j,最大化values[i] + i + values[j] - j的值。这个可以通过在遍历过程中保持values[i] + i的最大值来实现。
具体步骤
- 初始化一个变量
max_i = values[0] + 0,表示values[i] + i的最大值。 - 遍历数组中的每一个
j,计算出values[j] - j,然后将max_i与values[j] - j相加,得到当前的得分。 - 更新
max_i为values[j] + j中的最大值,继续向下遍历。
时间复杂度
- 我们只需要遍历一次数组,因此时间复杂度为
O(n),其中n是数组的长度。
java代码实现
public class MaxScenicScore {
public static int maxScoreSightseeingPair(int[] values) {
// 初始化 max_i 为第一个景点的得分
int max_i = values[0] + 0;
int maxScore = Integer.MIN_VALUE;
// 从第二个景点开始遍历
for (int j = 1; j < values.length; j++) {
// 计算当前的得分
maxScore = Math.max(maxScore, max_i + values[j] - j);
// 更新 max_i,表示从 i 到 j 之间所有景点中的最大值
max_i = Math.max(max_i, values[j] + j);
}
return maxScore;
}
public static void main(String[] args) {
// 示例1
int[] values1 = {8, 3, 5, 5, 6};
System.out.println("最大得分:" + maxScoreSightseeingPair(values1)); // 输出:11
// 示例2
int[] values2 = {10, 4, 8, 7};
System.out.println("最大得分:" + maxScoreSightseeingPair(values2)); // 输出:16
// 示例3
int[] values3 = {1, 2, 3, 4, 5};
System.out.println("最大得分:" + maxScoreSightseeingPair(values3)); // 输出:8
}
}
代码解释
-
maxScoreSightseeingPair方法:这是我们求解最大得分的核心方法。max_i初始化为第一个景点的得分(即values[0] + 0)。- 然后,我们开始从第二个景点
j = 1开始遍历。对于每一个景点j,我们计算出values[j] - j,并将其与max_i相加,得到当前的得分。 - 更新
max_i,它存储的是当前为止所有景点中values[i] + i的最大值。
-
main方法:这里用来测试函数,输出三个示例的最大得分。
测试案例分析
-
样例1: 输入:
values = [8, 3, 5, 5, 6]- 初始时,
max_i = 8 + 0 = 8。 - 对于
j = 1,values[1] - 1 = 3 - 1 = 2,当前得分8 + 2 = 10。 - 对于
j = 2,values[2] - 2 = 5 - 2 = 3,当前得分8 + 3 = 11。 - 对于
j = 3,values[3] - 3 = 5 - 3 = 2,当前得分8 + 2 = 10。 - 对于
j = 4,values[4] - 4 = 6 - 4 = 2,当前得分8 + 2 = 10。 - 最大得分为 11。
- 初始时,
-
样例2: 输入:
values = [10, 4, 8, 7]- 初始时,
max_i = 10 + 0 = 10。 - 对于
j = 1,values[1] - 1 = 4 - 1 = 3,当前得分10 + 3 = 13。 - 对于
j = 2,values[2] - 2 = 8 - 2 = 6,当前得分10 + 6 = 16。 - 对于
j = 3,values[3] - 3 = 7 - 3 = 4,当前得分10 + 4 = 14。 - 最大得分为 16。
- 初始时,
-
样例3: 输入:
values = [1, 2, 3, 4, 5]- 初始时,
max_i = 1 + 0 = 1。 - 对于
j = 1,values[1] - 1 = 2 - 1 = 1,当前得分1 + 1 = 2。 - 对于
j = 2,values[2] - 2 = 3 - 2 = 1,当前得分1 + 1 = 2。 - 对于
j = 3,values[3] - 3 = 4 - 3 = 1,当前得分1 + 1 = 2。 - 对于
j = 4,values[4] - 4 = 5 - 4 = 1,当前得分1 + 1 = 2。 - 最大得分为 8。
- 初始时,
总结
通过分析问题,我们发现可以将问题转化为一个较为简单的求最大值的问题。在代码中,我们通过一次遍历计算出每一对 (i, j) 的得分,并在过程中更新最大值。最终得到了高效的解法,时间复杂度为 O(n)。