给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。
一对景点(i < j)组成的观光组合的得分为(A[i] + A[j] + i - j):景点的评分之和减去它们两者之间的距离。
返回一对观光景点能取得的最高分。
https://leetcode-cn.com/problems/best-sightseeing-pair
暴力求解
对于没有任何算法基础的同学,最容易想到的做法是把所有可能性都计算一遍。
可以利用两层循环计算 A[i]+A[j]+i-j 的所有可能性的最大值。
n = len(A)
res = -n
for i in range(0,n):
for j in range(i+1,n):
res = max(res, A[i]+A[j]+i-j)
return res
复杂度分析:
- 时间上:代码中有两层循环,因此时间复杂度为 O(n^2)。
- 空间上:除了输入数组之外,只用了 res, n, i, j 四个变量,因此空间复杂度为 O(1)。
以上算法有没有可能优化一下呢?当然是可以的!
我们可以把评分和 A[i]+A[j]+i-j 分成两部分看待:A[i]+i 和 A[j]-j。
如果我们能预先计算并存储前 n 个景点中 A[i]+i 的最大值,再计算并存储后 n 个景点中 A[j]-j 的最大值,那么通过一遍循环就可以求得 A[i]+A[j]+i-j 的最大值了。
事实上,我们并不需要这么多数组来存放最大值。
如果我们再进一步优化,当从前往后循环时,存储并计算当前景点之前的A[i]+i 的最大值,并和当前景点评分 A[j]-j 相加。如果新得到的评分和比之前计算所得要高,那么更新最高评分和。完整代码:
复杂度分析:def maxScoreSightseeingPair(self, A: List[int]) -> int:
# 初始化
n = len(A)
max_start = A[0]
res = -n
for i in range(1,n):
# 计算以当前景点为后一个景点的最高评分
# 并和已有的最高分对比
res = max(res, A[i] - i + max_start)
# 维护前i个景点中A[i]+i的最大值
max_start = max(max_start, A[i] + i)
return res
- 时间上:代码中只有一层循环,循环次数为景点数。因此时间复杂度为O(n)。
- 空间上:除了输入数组之外,只用了 res, max_start, n, i 四个变量,因此空间复杂度为 O(1)。