青训营X豆包MarsCode 技术训练营 | 豆包MarsCode AI 刷题

133 阅读2分钟

问题描述

小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

思路分析

题目中给出了观光组合得分公式为values[i] + values[j] + i - j (i < j),初步的思路为暴力枚举,最外层循环遍历j,终止条件为j<n,里层循环遍历i,终止条件为i<j,找到最大的values[i] + values[j] + i - j。时间复杂度为O(n²)。

优化思路为维护一个最大的 values[i] + i,因为对于暴力思路中的内层循环而言,其最终的目的也是找到0~j的范围内最大的values[i] + i,我们可以使用一个值max_i维护它,每次遍历j的时候,首先计算出当前最大值max_i + values[j] -j,然后对max_i进行更新,当遍历完所有的j时,就得到了最大得分。

代码实现

#include <vector>
#include <iostream>

int solution(std::vector<int> values) {
    int n = values.size();
    int max_i = values[0] + 0;
   
    int max_score = 0;
    
    for( int i = 1;i < n;i++)
    {
        max_score = std::max(max_score, max_i + values[i] - i);
        max_i  = std::max(max_i , values[i] + i);
    }
    
    return max_score; 
}

代码解释

代码中,max_i代表了从第一个景点到当前景点i,考虑了景点评分和索引后的最大潜在得分。在每次迭代中,我们计算当前景点i和之前景点组合的得分,并更新最高得分max_score。同时,我们也更新max_i,以便在后续迭代中使用。

总结

代码的时间复杂度为O(n),因为它只需要遍历一次景点数组。刚开始解题的时候,如果没有好的思路,可以先用暴力思路进行求解。再从暴力思路中找到可以优化的点,进一步进行优化。对于本题使用的优化思路是枚举右,维护左的思路,这样可以避免每次都从头到尾进行遍历,而是通过动态维护某些信息,减少重复计算。这种思路在区间问题,滑动窗口问题中经常使用到。