Medium
题目描述
给你一个正整数数组 values,其中 values[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的 距离 为 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^41 <= values[i] <= 1000
解题思路
这道题的关键是理解得分公式的结构。对于一对景点 (i, j),其中 i < j,得分为:
values[i] + values[j] + i - j
我们可以将这个公式重新组织为:
(values[i] + i) + (values[j] - j)
这样分解后,问题就变成了:当我们遍历到位置 j 时,如何找到之前位置中 values[i] + i 的最大值。
解法思路:
- 暴力解法:枚举所有可能的
(i, j)对,时间复杂度 O(n²) - 动态规划优化:一次遍历,维护到当前位置为止的最大
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) | 只使用了常数额外空间 |