给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。 


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


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

https://leetcode-cn.com/problems/best-sightseeing-pair


LeetCode每日一题 | 最佳观光组合_java


暴力求解

对于没有任何算法基础的同学,最容易想到的做法是把所有可能性都计算一遍。


可以利用两层循环计算 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)