最佳观光组合

给定正整数数组  A,A[i]  表示第  i  个观光景点的评分,并且两个景点  i  和  j  之间的距离为  j  -  i。
一对景点(i  <  j)组成的观光组合的得分为(A[i]  +  A[j]  +  i  -  j):景点的评分之和减去它们两者之间的距离。

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

示例:

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

提示:

        2  <=  A.length  <=  50000
        1  <=  A[i]  <=  1000

自我解答(动态规划)

        显然,最佳组合  (i,  j),  其中  j  的位置,必定是列表中的其中一个,沿用  ”最大子序列和“  中的简化思路,
        将问题转化成  “求出以每个位置结尾的最佳组合分数“,  这样其中组合分数最大值,便是原问题的最优解。

        但我发现  分数本身并不存在递推关系,反而在枚举组合时发现了规律:
                假如枚举出  以  j  结尾的所有组合:
                                        (0,  j),  (1,  j)  ...  (j-1,  j)

                结合公式:  A[i]  +  A[j]  -  (j  -  i)
                (1,  j)  相对于  (0,  j)  来说,距离变近了,对于结果增益  +1
                因此,很容易判断,即使  A[1]  ==  A[0],也可以直接选  i  =  1,
                        事实上,只要  (A[1]  +  距离增益)  不低于  A[0]  就行了
                        递推到  A[j-1],便很容易从  A[0:j]  获得最佳起始位置

        由此,便能一路记录最佳的起始位置,记作  best_start:
                遍历到位置  j  时,通过    A[j]  +  (j  -  best_start)  >=  A[best_start]  更新  best_start
                则以位置  j+1  结尾的最佳组合就是  (best_start,  j+1)

        到这里,最优子结构就很清晰了:
                记  f(j):  以  位置  j  结尾的最佳起始位置
                f(j+1)  =  j  if  A[j]  +  j  -  f(j)  >=  A[f(j)]  else  f(j)

由此写出  自底向上的动态规划算法

class Solution:
    def maxScoreSightseeingPair(self, A: List[int]) -> int:
        best_start, max_score = 0, A[1] + A[0] - 1
        for i in range(1, len(A) - 1):
            if A[i] + (i - best_start) >= A[best_start]:
                best_start = i
            score = A[i + 1] + A[best_start] - (i + 1 - best_start)
            if score > max_score:
                max_score = score
        return max_score

原题链接:https://leetcode-cn.com/problems/best-sightseeing-pair