青训营X豆包MarsCode--观光景点组合得分问题 题解 | 豆包MarsCode AI刷题

43 阅读6分钟

观光景点组合得分问题

问题描述

小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

Code:


using namespace std;

int solution(vector<int> values) {
    if(values.size() == 1) return 0;
    int maxv = 0 , res = 0;

    for(int i = 0 ; i < values.size() ; i ++)
    {
        res = max(res , values[i] - i + maxv);
        maxv = max(maxv , values[i] + i);
    }
    return res; // Placeholder return
}

int main() {
    cout << (solution({8, 3, 5, 5, 6}) == 11) << endl;
    cout << (solution({10, 4, 8, 7}) == 16) << endl;
    cout << (solution({1, 2, 3, 4, 5}) == 8) << endl;
    return 0;
}

题目分析与理解

在这个问题中,我们给定了一个整数数组 values,目标是通过某种特定的方式计算并找到最大值。通过分析代码,发现问题的本质在于结合数组中的元素值及其索引,通过特定的公式来计算出一个结果。

在这个过程中,最关键的步骤是理解公式 res = max(res, values[i] - i + maxv)maxv = max(maxv, values[i] + i) 的含义及其计算逻辑。下面我们将详细分析题目的要求,逐步解析代码的实现,并总结出解题的思路和优化方法。

问题的关键公式

题目中的核心公式是:
res = max(res, values[i] - i + maxv)

maxv = max(maxv, values[i] + i)

我们需要通过这两个公式来找到最大值。这是基于以下几方面的考虑:

  1. 数组元素与其索引的关系:

    • 对于数组中的每个元素 values[i],我们要考虑它与其索引 i 结合后的某种表现形式,计算出一个最优值。
    • 通过公式 values[i] - i + maxv,我们希望得到当前元素 values[i] 与它的索引 i 的差值,并加上之前计算出的最大参考值 maxv
  2. maxv 的更新:

    • maxv = max(maxv, values[i] + i),该公式的意思是我们要保持追踪数组中每个元素与其索引 i 相加后的最大值。maxv 记录的是迄今为止,我们计算出的最大参考值。
    • 通过这个更新过程,我们能够保持一个有效的历史记录,在后续的计算中使用这些最大值来与当前的值做对比,从而得到最优的结果。

解题思路分析

本题的思路实际上是通过动态维护一个历史最大值 maxv 来避免重复计算,并且通过每次计算 values[i] - i + maxv 来得到一个新的可能最大值。我们将这个过程逐步分解如下:

  1. 初始化:

    • maxv 初始化为 0,它将用于记录数组中每个位置之前(包括当前位置)的最大值 values[i] + i
    • res 初始化为 0,用于记录当前计算过程中的最大值。最终的输出结果就是 res 的值。
  2. 遍历数组:

    • 遍历数组 values 中的每个元素 values[i],对每个元素,使用公式 res = max(res, values[i] - i + maxv) 进行更新。

      • 其中,values[i] - i 是当前元素和索引的差,maxv 是历史最大值,表示此前元素索引加值的最大值。
      • 每次更新 res 时,计算出当前值与历史最大值结合的最优解。
    • 然后,更新 maxvmax(maxv, values[i] + i),即比较当前值和索引相加的结果与之前的 maxv,保持 maxv 为最大的参考值。

  3. 结束遍历,输出结果:

    • 当遍历完所有元素后,res 存储了我们要求的最大值。

代码实现分析

#include <bits/stdc++.h>
using namespace std;

int solution(vector<int> values) {
    if(values.size() == 1) return 0;
    int maxv = 0, res = 0;

    for(int i = 0 ; i < values.size() ; i++) {
        res = max(res, values[i] - i + maxv);
        maxv = max(maxv, values[i] + i);
    }
    return res; // Placeholder return
}

int main() {
    cout << (solution({8, 3, 5, 5, 6}) == 11) << endl;
    cout << (solution({10, 4, 8, 7}) == 16) << endl;
    cout << (solution({1, 2, 3, 4, 5}) == 8) << endl;
    return 0;
}
1. 初始化部分
int maxv = 0, res = 0;

这两行代码分别初始化了 maxvresmaxv 用来追踪到当前位置为止最大的 values[i] + ires 用来存储每次计算得到的最大结果。

2. 遍历部分
for(int i = 0; i < values.size(); i++) {
    res = max(res, values[i] - i + maxv);
    maxv = max(maxv, values[i] + i);
}

这个循环遍历了数组中的所有元素。每次循环都用 values[i] - i + maxv 计算当前可能的最大值,并更新 maxv。通过不断更新 resmaxv,我们确保能够找到最终的最大结果。

3. 输出结果
return res;

返回最终的最大值 res,这是我们经过遍历和计算得到的结果。

示例分析

示例 1

输入:{8, 3, 5, 5, 6}

  • 初始时,maxv = 0res = 0

  • 遍历每个元素:

    • i = 0res = max(0, 8 - 0 + 0) = 8,更新 maxv = max(0, 8 + 0) = 8
    • i = 1res = max(8, 3 - 1 + 8) = 10maxv = max(8, 3 + 1) = 8
    • i = 2res = max(10, 5 - 2 + 8) = 11maxv = max(8, 5 + 2) = 7
    • i = 3res = max(11, 5 - 3 + 8) = 11maxv = max(7, 5 + 3) = 8
    • i = 4res = max(11, 6 - 4 + 8) = 11maxv = max(8, 6 + 4) = 10
  • 最终结果为 11

示例 2

输入:{10, 4, 8, 7}

  • 初始时,maxv = 0res = 0

  • 遍历每个元素:

    • i = 0res = max(0, 10 - 0 + 0) = 10,更新 maxv = max(0, 10 + 0) = 10
    • i = 1res = max(10, 4 - 1 + 10) = 13maxv = max(10, 4 + 1) = 10
    • i = 2res = max(13, 8 - 2 + 10) = 16maxv = max(10, 8 + 2) = 10
    • i = 3res = max(16, 7 - 3 + 10) = 16maxv = max(10, 7 + 3) = 10
  • 最终结果为 16

时间与空间复杂度分析

  • 时间复杂度:
    本算法的时间复杂度为 O(n),其中 n 是数组 values 的长度。我们只遍历了一次数组,计算每个元素的值,因此时间复杂度为线性。
  • 空间复杂度:
    空间复杂度为 O(1),因为我们只用了常数个额外变量 maxvres 来存储计算结果。

总结

  1. 本题考察了动态更新和参考最大值的技巧,通过不断更新 maxvres,我们能够在一次遍历中获得最终的最大结果。
  2. 通过有效地使用前缀最大值技巧,我们成功减少了重复计算,提高了算法的效率。
  3. 时间和空间复杂度均为 O(n)O(1) ,算法效率较高,能够适应题目要求的输入规模。