题目解析:观光景点组合得分问题
小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这道题目要求你在给定的观光景点评分数组中,找到两个景点的组合(i, j)(满足i < j),使得它们的组合得分最大。组合得分的计算公式是:
[ \text{得分} = \text{values}[i] + \text{values}[j] + i - j ]
这个公式可以拆解为以下两部分:
values[i] + values[j]:两景点的评分之和。i - j:这两个景点之间的距离。
我们需要通过对 values 数组中所有可能的景点对 (i, j)(即 i < j)计算得分,找到得分最大的组合。
解题思路
首先来看一下公式:
[ \text{得分} = \text{values}[i] + \text{values}[j] + i - j ]
我们可以将公式改写为:
[ \text{得分} = (\text{values}[i] + i) + (\text{values}[j] - j) ]
从上面的表达式中,我们可以得出以下的推论:
- 对于每个景点
i,我们可以计算出values[i] + i这一项,这个值是固定的,只与当前位置i和评分values[i]相关。 - 对于每个景点
j,我们可以计算出values[j] - j这一项,这个值只与j和评分values[j]相关。
于是我们就得到了一个优化问题:对于所有的景点对 (i, j)(i < j),我们要找出 values[i] + i 和 values[j] - j 的最大值之和。这样,问题就转化成了:找出 values[i] + i 的最大值和 values[j] - j 的最大值。
实现过程
-
定义辅助数组:
- 定义
leftMax来存储values[i] + i的最大值。 - 遍历数组,通过计算
leftMax来逐步更新当前最大得分。
- 定义
-
计算每个可能的得分:
- 对于每个景点
j,计算values[j] - j并与leftMax中存储的最大值相加。
- 对于每个景点
-
维护最大得分:
- 每次更新当前的最大得分,最终输出结果。
代码实现
javaCopy Code
public class Main {
public static int solution(int[] values) {
// 初始化
int maxScore = Integer.MIN_VALUE;
int leftMax = values[0] + 0; // 初始值是第一个景点的 values[i] + i
// 从第二个景点开始遍历
for (int j = 1; j < values.length; j++) {
// 计算当前景点 j 的 values[j] - j
int rightPart = values[j] - j;
// 更新最大得分
maxScore = Math.max(maxScore, leftMax + rightPart);
// 更新 leftMax,即记录所有 i < j 时的 values[i] + i 的最大值
leftMax = Math.max(leftMax, 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用于存储当前的最大得分,初始值为Integer.MIN_VALUE。leftMax用来记录values[i] + i的最大值,初始时设为values[0] + 0(即第一个景点的得分)。
-
遍历:
- 从第二个景点(即
j = 1)开始遍历数组。 - 计算当前景点
j的值:rightPart = values[j] - j。 - 通过比较当前的最大得分
maxScore和leftMax + rightPart来更新maxScore。
- 从第二个景点(即
-
更新
leftMax:- 在每次循环中,更新
leftMax为values[j] + j的最大值,这样确保在下次循环时,leftMax始终是前面所有景点i的最大值。
- 在每次循环中,更新
时间复杂度
- 时间复杂度:由于我们只需要遍历一次数组,并在每次循环中执行常数时间的操作,因此时间复杂度是 O(n) ,其中
n是数组values的长度。 - 空间复杂度:只用了常数空间(
maxScore和leftMax),因此空间复杂度是 O(1) 。
示例分析
示例 1:
输入:values = [8, 3, 5, 5, 6]
-
初始化:
leftMax = 8 + 0 = 8,maxScore = Integer.MIN_VALUE -
遍历
j从 1 到 4:j = 1:rightPart = 3 - 1 = 2,maxScore = max(8, 8 + 2) = 10j = 2:rightPart = 5 - 2 = 3,maxScore = max(10, 8 + 3) = 11j = 3:rightPart = 5 - 3 = 2,maxScore = max(11, 8 + 2) = 11j = 4:rightPart = 6 - 4 = 2,maxScore = max(11, 8 + 2) = 11
结果:最大得分为 11。
示例 2:
输入:values = [10, 4, 8, 7]
-
初始化:
leftMax = 10 + 0 = 10,maxScore = Integer.MIN_VALUE -
遍历
j从 1 到 3:j = 1:rightPart = 4 - 1 = 3,maxScore = max(10, 10 + 3) = 13j = 2:rightPart = 8 - 2 = 6,maxScore = max(13, 10 + 6) = 16j = 3:rightPart = 7 - 3 = 4,maxScore = max(16, 10 + 4) = 16
结果:最大得分为 16。
总结
通过将原来的得分公式 values[i] + values[j] + i - j 转化为 values[i] + i 和 values[j] - j 之和,我们可以通过一次遍历来有效地计算出最大得分,减少了计算的复杂度,使得问题的时间复杂度降低到 O(n)。
心得:
使用MarsCode AI编写代码让我体验到了编程的便利与高效。AI能够快速生成代码示例,帮助我理解不同编程概念。通过交互式的反馈,我能迅速调整思路,解决问题。同时,MarsCode AI提供的建议让我了解到更多最佳实践,提升了我的编码水平。这种工具不仅节省了时间,还激发了我的创造力,尤其是在处理复杂问题时,AI的支持显得尤为重要。总的来说,MarsCode AI是编程学习和实践中的得力助手。