Medium

题目描述

给你一个正整数数组 values,其中 values[i] 表示第 i 个观光景点的评分,并且两个景点 ij 之间的 距离j - i

一对景点(i < j)组成的观光组合的得分为 values[i] + values[j] + i - j,也就是景点的评分之和 减去 它们两者之间的距离。

返回一对观光景点能取得的最高分。

示例 1:

输入:values = [8,1,5,2,6]
输出:11
解释:i = 0, j = 2, values[i] + values[j] + i - j = 8 + 5 + 0 - 2 = 11

示例 2:

输入:values = [1,2]
输出:2

提示:

  • 2 <= values.length <= 5 * 10^4
  • 1 <= values[i] <= 1000

解题思路

这道题的关键是理解得分公式的结构。对于一对景点 (i, j),其中 i < j,得分为: values[i] + values[j] + i - j

我们可以将这个公式重新组织为: (values[i] + i) + (values[j] - j)

这样分解后,问题就变成了:当我们遍历到位置 j 时,如何找到之前位置中 values[i] + i 的最大值。

解法思路:

  1. 暴力解法:枚举所有可能的 (i, j) 对,时间复杂度 O(n²)
  2. 动态规划优化:一次遍历,维护到当前位置为止的最大 values[i] + i

推荐解法:动态规划

  • 用变量 maxLeft 维护到当前位置为止的最大 values[i] + i
  • 对于每个位置 j,计算 maxLeft + values[j] - j 的值
  • 更新结果的最大值,并更新 maxLeft

这种方法只需要一次遍历,时间复杂度为 O(n),空间复杂度为 O(1)。

代码实现

class Solution {
public:
    int maxScoreSightseeingPair(vector<int>& values) {
        int maxLeft = values[0];  // values[0] + 0
        int result = 0;
        
        for (int j = 1; j < values.size(); j++) {
            result = max(result, maxLeft + values[j] - j);
            maxLeft = max(maxLeft, values[j] + j);
        }
        
        return result;
    }
};
class Solution:
    def maxScoreSightseeingPair(self, values: List[int]) -> int:
        max_left = values[0]  # values[0] + 0
        result = 0
        
        for j in range(1, len(values)):
            result = max(result, max_left + values[j] - j)
            max_left = max(max_left, values[j] + j)
        
        return result
public class Solution {
    public int MaxScoreSightseeingPair(int[] values) {
        int maxLeft = values[0];  // values[0] + 0
        int result = 0;
        
        for (int j = 1; j < values.Length; j++) {
            result = Math.Max(result, maxLeft + values[j] - j);
            maxLeft = Math.Max(maxLeft, values[j] + j);
        }
        
        return result;
    }
}
var maxScoreSightseeingPair = function(values) {
    let maxLeft = values[0];  // values[0] + 0
    let result = 0;
    
    for (let j = 1; j < values.length; j++) {
        result = Math.max(result, maxLeft + values[j] - j);
        maxLeft = Math.max(maxLeft, values[j] + j);
    }
    
    return result;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(n)只需要遍历数组一次
空间复杂度O(1)只使用了常数额外空间