观光景点组合得分问题

90 阅读3分钟

问题描述

小R正在研究一组观光景点,每个景点有一个评分,存储在数组 values 中,values[i] 表示第 i 个景点的评分。同时,景点之间的距离由它们的下标差 j - i 表示。

对于任意一对景点 (i < j),它们的观光组合得分计算方式为:

得分 = values[i] + values[j] + (i - j)

即,两景点的评分之和减去它们之间的距离。

小R的目标是找出在哪种情况下能够获得观光景点组合的最高得分。

思路分析

首先,问题的关键是理解观光组合得分的计算公式:

得分 = values[i] + values[j] + (i - j)

我们可以将这个公式稍微变形为:

得分 = (values[i] + i) + (values[j] - j)

从这里可以看到,对于任意的 ij,我们需要关注的其实是 values[i] + ivalues[j] - j 的值。

所以,我们可以通过以下方式来优化解法:

  1. 预处理两个新的数组:

    • score1[i] = values[i] + i,即每个景点的评分加上其下标。
    • score2[i] = values[i] - i,即每个景点的评分减去其下标。
  2. 最大化组合得分:

    • 要找到一对景点 (i, j),使得 score1[i] + score2[j] 最大,其中 i < j
    • 这意味着,随着 j 的增加,我们可以记录到当前的 score1 的最大值(记为 max_score1),然后计算当前的得分 max_score1 + score2[j],更新最大得分。
  3. 优化思路:

    • 对于每个 j,我们可以通过提前计算 score1 中的最大值来快速求解最优得分,从而减少不必要的计算。

时间复杂度

  • 时间复杂度为 O(n),其中 n 是 values 数组的长度。我们只需要一次遍历数组来计算 score1score2,并同时求出最大得分。

Java代码实现

public class  Main {
    public int solution(int[] values) {
        int maxScore = Integer.MIN_VALUE;
        int maxScore1 = values[0]; // 初始化为第一个景点的评分加下标

        // 遍历数组,计算最大得分
        for (int j = 1; j < values.length; j++) {
            // 计算当前的得分
            int score = maxScore1 + values[j] - j;
            // 更新最大得分
            maxScore = Math.max(maxScore, score);
            // 更新maxScore1(即max(values[i] + i))
            maxScore1 = Math.max(maxScore1, 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 用于保存当前的最大得分,初始值为负无穷。
    • maxScore1 用于保存到当前位置的 values[i] + i 的最大值,初始值为第一个景点的评分加上其下标(即 values[0] + 0)。
  2. 遍历数组

    • j = 1 开始遍历数组(i 会在前面的循环中用到)。
    • 对于每一个 j,我们通过 maxScore1 来获取最大可能的 values[i] + i,然后计算当前的得分,并更新最大得分。
    • 更新 maxScore1 为当前 values[j] + j 和之前的最大值中的较大者。
  3. 输出结果

    • 最后,返回 maxScore,即最优的观光组合得分。

测试用例分析

  • 样例1

    • 输入:values = [8, 3, 5, 5, 6]
    • 输出:11
    • 解释:最优的景点组合是 (i=0, j=3),得分为 8 + 5 + 0 - 3 = 11
  • 样例2

    • 输入:values = [10, 4, 8, 7]
    • 输出:16
    • 解释:最优的景点组合是 (i=0, j=2),得分为 10 + 8 + 0 - 2 = 16
  • 样例3

    • 输入:values = [1, 2, 3, 4, 5]
    • 输出:8
    • 解释:最优的景点组合是 (i=0, j=4),得分为 1 + 5 + 0 - 4 = 8

总结

这个问题的关键在于转化计算方式,通过预先计算 values[i] + ivalues[i] - i,我们能够以线性的时间复杂度完成遍历并获得最优解。通过这种方式,避免了暴力方法中对每对 (i, j) 的遍历,提高了效率。