每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair

2020年6月17日 最佳观光组合 maxScoreSightseeingPair

每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第1张图片

默认格式:

class Solution {
    public int maxScoreSightseeingPair(int[] A) {

    }
}

解题思路:

没有解题思路之前,暴力算法先解决了一下。

这道题的意思,找到两个点,他们的值相加并且下标相减得到一个数值,计算这个数值的最大值。
每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第2张图片

    public int maxScoreSightseeingPair(int[] A) {
        int res=A[0];

        for (int i=0;i<A.length;i++){
            for (int j=i+1;j<A.length;j++)
            {
                res=Math.max(res, A[i]+A[j]+i-j);
            }
        }
        return res;
    }

果然超出时间限制。所以我们要对其进行优化。

我们找到链各个相邻的点,i和i+1,计算他们到j的值,可以得到下面的关系

A[i]+A[j]+i-j-(A[i+1]+A[j]+i+1-j)=A[i]-A[i+1]-1

如果A[i]-A[i+1]-1>0 ,表示i到j的值比i+1到j的值大,即我们可以得到 A[i]>A[i]+1

我们不难发现一点,如果A[i]的值比A[i+1]的值要小,那么A[i]+A[j]+i-j必定会比A[i+1]+A[j]+i+1-j小,同理

如果A[i]的值比A[i+1]的值要大超过1。

我们可以延伸得到

A[i]>A[i+x]+x则i+x到j的值比i大

在思考的过程中,我想到了一种使用滑动窗口的方式来实现该算法。

刚开始,起点和终点在同一位置,返回值也是0。

然后end后移,寻找能够替代start的存在的坐标,使任意的j>end都能实现A[end]+A[j]+end-j>A[star]+A[j]+start-j

所以找到了下标是1的100,此时记下val197

每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第3张图片

start右移,找到start-end之见最大的值,直到start到达end
每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第4张图片

然后将end向右移,直到val大于197,找到下标7的494
每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第5张图片

此时start再次右移,记下中间得到的最大的值499

每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第6张图片

此时end继续右移,找到400的替代品

正确性验证。

由于我们规定寻找end比start要大的值,所以end+start的值必定比中间任意两个值得到的结果更大。

因为end+start>2start,而中间的两个值相加得到的必定小于2start。

然后计算start之间到end之间最大的值,得到的值必定小于2end的值的大小。

思路已经有了,下面就是代码了。

但是现在有另外一种思路:

为什么不直接记下对于右边最优的位置,因为我们可以计算出一个位置比其他小于j的所有值都大,然后右边的所有值都只要和最大的比,不需要和前面的每一个值进行对比了。

代码如下
每日一题算法:2020年6月17日 最佳观光组合 maxScoreSightseeingPair_第7张图片

public int maxScoreSightseeingPair(int[] A) {
    int ans = 0;
    int max = A[0] + 0;
    for (int j = 1; j < A.length; ++j) {
        ans = Math.max(ans, max + A[j] - j);
        max = Math.max(max, A[j] + j);
    }
    return ans;
}

你可能感兴趣的:(每日一题算法)