观光景点组合得分问题| 豆包MarsCode AI 刷题

98 阅读5分钟

题目解析:观光景点组合得分问题

小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] + ivalues[j] - j 的最大值之和。这样,问题就转化成了:找出 values[i] + i 的最大值和 values[j] - j 的最大值。

实现过程

  1. 定义辅助数组

    • 定义 leftMax 来存储 values[i] + i 的最大值。
    • 遍历数组,通过计算 leftMax 来逐步更新当前最大得分。
  2. 计算每个可能的得分

    • 对于每个景点 j,计算 values[j] - j 并与 leftMax 中存储的最大值相加。
  3. 维护最大得分

    • 每次更新当前的最大得分,最终输出结果。

代码实现

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);
    }
}

代码解析

  1. 初始化

    • maxScore 用于存储当前的最大得分,初始值为 Integer.MIN_VALUE
    • leftMax 用来记录 values[i] + i 的最大值,初始时设为 values[0] + 0(即第一个景点的得分)。
  2. 遍历

    • 从第二个景点(即 j = 1)开始遍历数组。
    • 计算当前景点 j 的值:rightPart = values[j] - j
    • 通过比较当前的最大得分 maxScore 和 leftMax + rightPart 来更新 maxScore
  3. 更新 leftMax

    • 在每次循环中,更新 leftMax 为 values[j] + j 的最大值,这样确保在下次循环时,leftMax 始终是前面所有景点 i 的最大值。

时间复杂度

  • 时间复杂度:由于我们只需要遍历一次数组,并在每次循环中执行常数时间的操作,因此时间复杂度是 O(n) ,其中 n 是数组 values 的长度。
  • 空间复杂度:只用了常数空间(maxScoreleftMax),因此空间复杂度是 O(1)

示例分析

示例 1:

输入:values = [8, 3, 5, 5, 6]

  • 初始化:leftMax = 8 + 0 = 8maxScore = Integer.MIN_VALUE

  • 遍历 j 从 1 到 4:

    • j = 1rightPart = 3 - 1 = 2maxScore = max(8, 8 + 2) = 10
    • j = 2rightPart = 5 - 2 = 3maxScore = max(10, 8 + 3) = 11
    • j = 3rightPart = 5 - 3 = 2maxScore = max(11, 8 + 2) = 11
    • j = 4rightPart = 6 - 4 = 2maxScore = max(11, 8 + 2) = 11

结果:最大得分为 11。

示例 2:

输入:values = [10, 4, 8, 7]

  • 初始化:leftMax = 10 + 0 = 10maxScore = Integer.MIN_VALUE

  • 遍历 j 从 1 到 3:

    • j = 1rightPart = 4 - 1 = 3maxScore = max(10, 10 + 3) = 13
    • j = 2rightPart = 8 - 2 = 6maxScore = max(13, 10 + 6) = 16
    • j = 3rightPart = 7 - 3 = 4maxScore = max(16, 10 + 4) = 16

结果:最大得分为 16。

总结

通过将原来的得分公式 values[i] + values[j] + i - j 转化为 values[i] + ivalues[j] - j 之和,我们可以通过一次遍历来有效地计算出最大得分,减少了计算的复杂度,使得问题的时间复杂度降低到 O(n)。

心得:

使用MarsCode AI编写代码让我体验到了编程的便利与高效。AI能够快速生成代码示例,帮助我理解不同编程概念。通过交互式的反馈,我能迅速调整思路,解决问题。同时,MarsCode AI提供的建议让我了解到更多最佳实践,提升了我的编码水平。这种工具不仅节省了时间,还激发了我的创造力,尤其是在处理复杂问题时,AI的支持显得尤为重要。总的来说,MarsCode AI是编程学习和实践中的得力助手。